how to stop the setTimeout recursion - javascript

I have created the setTimeout which has a callback named run, Inside the run I have called a console.log(i) to print the value of I with i++ and once it reaches to 50, I want to clear the setTimeout with clearTimeout, I am calling setTimeout again with run making it recursive, but it doesn't work.
can somebody help me understand the concept better?
let i = 1;
var abc = setTimeout(function run(){
console.log(i);
if(i==50){
abc1();
}
i++;
setTimeout(run,100);
},100);
function abc1(){
clearTimeout(abc);
}

When you call setTimeout you get the ID of the timer returned. It's exactly what you've done here:
var abc = setTimeout(function run(){
However, that ID is valid only until the delayed function executes. Once it does, it's ineffective. When you call setTimeout(run,100); you will get a new ID for the timer. You need to capture that again, otherwise the ID gets lost and you have no way to stop it.
There is a final consideration - with your current code even if you were to correctly capture the ID calling abc = setTimeout(run, 100); that would still not stop the counter because it will attempt to stop the function that is running right now (which does nothing), instead of cancelling the execution of the next one:
let i = 1;
var abc = setTimeout(function run() {
console.log(i);
if (i == 50) {
abc1(); //this will clear the *current* timer
}
i++;
abc = setTimeout(run, 100); //this will set the *new* ID
}, 100);
function abc1() {
clearTimeout(abc);
}
In order to stop the execution you have two options. If you want to use your initial idea, you need to cancel the future execution after it is scheduled
let i = 1;
var abc = setTimeout(function run() {
console.log(i);
abc = setTimeout(run, 100); //this will set the *new* ID
if (i == 50) {
abc1(); //this will clear the *new* timer now
}
i++;
}, 100);
function abc1() {
clearTimeout(abc);
}
Alternatively, you can do it without using timer handles at all and just use the if condition to determine if you want to schedule another execution or not:
let i = 1;
setTimeout(function run() {
console.log(i);
if (i != 50) { //until 50 is reached
abc = setTimeout(run, 100); //schedule a new execution
}
i++;
}, 100);

The problem is the order of your operations.
if(i==50){
abc1();
}
If i reaches 50, the function abc1() will be called - which clears the interval.
i++;
setTimeout(run,100);
here you're restarting the interval.
You need to wrap it inside an else block.
let i = 1;
var abc = setTimeout(function run() {
console.log(i);
if (i == 50) {
abc1();
} else {
i++;
setTimeout(run, 100);
}
}, 100);
function abc1() {
clearTimeout(abc);
}

let i = 1;
var abc = setTimeout(function run(){
console.log(i);
if(i<50){
setTimeout(run,100);
}
i++;
},100);
You should run timeout only if timer not run out.

The setTimeout() inside run() in not assigned to any variable so it can't be cleared in any manner.
I suppose what you want is to overwrite abc so you must replace:
setTimeout(run,100);
by
abc = setTimeout(run,100);

Since var abc is only set once, at the first timeout, you are clearing only the very first Timeout, which very likely is already complete.
SetTimeout returns a numeric value, which is an ID to refer to that task. When you call clearTimeout, you must inform the ID of the timeout you want to clear, and now you are informing the ID for the very first timeout, which is already finished, thus can't be cleared.
If you wish to clear the last timeout, maybe you would like to always update abc with the IDs for each timeout, like this:
abc = setTimeout(run,100);

This is a weird way of doing a timed loop but you just need to clear (actually not in this case but I like to do it anyway as it is a good practice to release resources once you don't use them anymore) the timeouts (done by keeping track of abc handle) before creating new ones and return after clear on the given condition:
let i = 1;
let abc = setTimeout(
function run(){
console.log(i);
if(i==50){
abc1();
return;
}
abc1();
i++;
abc = setTimeout(run,100);
},
100
);
function abc1(){
clearTimeout(abc);
}

you need to add return after you call abc1 function. you clear timeout, but then code still running and call setTimeout(run,100) again.
let i = 1;
var abc = setTimeout(function run(){
console.log(i);
if(i==50){
abc1();
return;
}
i++;
setTimeout(run,100);
},100);
function abc1(){
clearTimeout(abc);
}

Related

How to use setInterval to trigger a function so that I can stop it at some point?

So from what I have understood, setInterval() is used to call a function on repeat on regular intervals.
So basically it is a loop that executes a function forever periodically.
I am confused as to if I had to stop this execution at one point what would be the way to do it
for eg I am trying to print the message "hey" 3 times after 1 second each, but somehow it is printing it 3 times every second and is going on forever.
What can I do to stop it after a set number of times.
This is the code that I've been trying
var i = 3;
function message() {
console.log("hey");
}
while(i > 0) {
setInterval(message, 1000);
i = i - 1;
}
Your code is executing the setInterval thrice in the while loop, which is not needed.
Actually, setInterval does not work as a function call but actually registers a function to be called at some interval.
The setInterval() method will continue calling the function until clearInterval() i.e it is deregistered or the process is killed.
It should work like this
var i = 3;
var interval = setInterval(message, 1000);
function message() {
if (i === 0) {
clearInterval(interval);
}
console.log("hey");
i = i - 1;
}
To clear a setInterval, use global clearInterval method.
Example:
var timerId = setInterval(func, 500);
.... some code here....
clearInterval(timerId);
What can I do to stop it after a set number of times.
usually you don't use setInterval() for this, you use setTimeout().
Something like
var counter = 0;
function message() {
console.log("hey");
// we trigger the function again after a second, if not already done 3 times
if (counter < 3) {
setTimeout(message, 1000);
}
counter++;
}
// initial startup after a second, could be faster too
setTimeout(message, 1000);
The setInterval function calls the function indefinitely, whereas setTimeout calls the function once only.
Simply use clearInterval once the count runs out.
var i = 3;
function message(){
console.log("hey");
if (--i < 0) {
clearInterval(tmr);
}
}
var tmr = setInterval(message, 1000);
you have to assign that setInterval to a javascript variable to name it what for this setInterval, like this
var messageLog = setInterval(message, 1000);
After, in setInterval message function add this condition to clear the inverval whenever you want to clear.
function message(){
if(i>3) {
clearInterval(messageLog); // clearInterval is a javascript function to clear Intervals.
return null;
}
console.log("hey");
}
You can retrieve the timer when creating and clear it if needed.
var i=3;
var timer = setInterval(message,1000);
function message(){
console.log("hey");
iā€”-;
if(i==0)
clearInterval(timer)
}
a beginner here too,look for clearInterval method ...

How to exec a function after previous ends?

guys. It's a timer. I wanna run the timer and when it's end do something else(like a warning),and then run again with other amount of minutes. But I can't cause always only the second call is executed:
$(document).ready(function() {
timer(5,timer(25));
// timer(5);
// timer(25); do not work... only exec de last one
});
function timer(countTo,callback){
var time = 10; /* how long the timer runs for */
var initialOffset = '440';
var i = 1
var interval = setInterval(function() {
$('.circle_animation').css('stroke-dashoffset', initialOffset-(i*(initialOffset/countTo)));
$('h2').text(i);
if (i == countTo) {
clearInterval(interval);
}
i++;
}, 1000);
callback();
}
Which is the best solution? There is something that I am not understanding... Thanks anyway!
Well, first off:
timer(5,timer(25));
If you think this line will execute timer(5), and then at the end of timer(5) it will execute timer(25), you are mistaken. This is actually going to evaluate timer(25) immediately, and pass its return value (undefined) as the second parameter to timer(5,undefined).
If you intended to pass that as a callback, you need to pass a function. So you could do:
timer(5,timer.bind(null,25));
But, for that matter, you don't even check if callback exists before attempting to invoke it, so you probably are getting a reference error anyway.
timer(5,timer(25));
starts two timers and passes the result of the second (undefined) to the first as callback. You want:
timer(5,timer.bind(window,25));
And the callback needs to be executed if i==countTo ...
Is this what you want?
timer(5,function(){timer(25)});
Your problem is here:
timer(5,timer(25));
You should type
timer(5, function(){
timer(25)
});
//or using ES6 syntax
timer(5, () => timer(25));
because timer(25) returns its value (this function doesn't return value so it tries to invoke undefined), not that function.
Also read about closures, it might be helpful.
Instead of runing a callback(), you need to run the function itself (timer()). You'll also need to run a for loop inside your function that checks how many times the function has already run. If it reaches your desired maximum, break out of that. This way it won't run indefinitely.
In the following example, the timer() function executes five times, which is what I'm assuming you want by calling timer(5).
$(document).ready(function() {
timer(5);
});
function timer(countTo) {
for (var iterations = 0; iterations < countTo; iterations++) {
var time = 10; /* how long the timer runs for */
var initialOffset = '440';
var i = 1
var interval = setInterval(function() {
$('.circle_animation').css('stroke-dashoffset', initialOffset - (i * (initialOffset / countTo)));
$('h2').text(i);
if (i == countTo) {
clearInterval(interval);
}
}, 1000);
timer();
console.log("Iteration:", iterations + 1);
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
To run the function 25 times after this, all you have to do is call timer(25) directly after timer(5):
$(document).ready(function() {
timer(5);
timer(25);
});
$(document).ready(function() {
timer(5);
timer(25);
});
function timer(countTo) {
for (var iterations = 0; iterations < countTo; iterations++) {
var time = 10; /* how long the timer runs for */
var initialOffset = '440';
var i = 1
var interval = setInterval(function() {
$('.circle_animation').css('stroke-dashoffset', initialOffset - (i * (initialOffset / countTo)));
$('h2').text(i);
if (i == countTo) {
clearInterval(interval);
}
}, 1000);
timer();
console.log("Iteration:", iterations + 1);
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Hope this helps! :)

Javascript function setTimeout and setIntervall not working

I've got this Problem here, that this function is not working and I cant figure out why..
This function should count to 10 (in 10 seconds). For this purpose I'm using a for loop with setTimeout function - duration set to 1000ms.
It should go on and on for what i took the setInterval function.
function timer() {
var time=10;
for(i=0; i<time; i++){
setTimeout(console.log(i+1), 1000);
}
}
setInterval(timer, 10000);
The Problem is, that it isnt working and I dont understand why ... I have found another working solution but would like to know the issue of this one. :)
The reason that nothing appears to happen is the way that you use setTimeout. Instead of providing an event handler you are calling console.log and try to use the return value from that call as event handler.
The closest thing that would at least do something would be to make a function that calls console.log:
setTimeout(function(){ console.log(i+1) }, 1000);
However, you will notice that it will just log the value 11 ten times at once, every ten seconds, indefinitely.
Eventhough the loop counts from 0 to 9, you start a timeout in each iteration that will be triggered one second from when it was created. As all ten timeouts are created at the same time, they will be triggered at the same time. There isn't a separate variable i for each handler, so they will all show the value in the variable at the time that they are triggered, and as the loop has completed before any of them can be called they will all show the final value 10 + 1.
You are using both an interval and timeouts, you should use one or the other.
You can start timeouts in a loop, but then you should only do it once, not in an interval, and you should specify the time from start to when you want it to be triggered:
var time = 10;
for (var i = 1; i <= time; i++){
setTimeout(function() { console.log('tick'); }, 1000 * i);
}
If you want to use the variable in the event handler, then you need to create a copy of the variable for each iteration:
var time = 10;
for (var i = 1; i <= time; i++){
(function(copy){
setTimeout(function() { console.log(copy); }, 1000 * i);
})(i);
}
You can use an interval, but then you don't have a loop, it's the interval that is the loop. Use clearInterval to stop it when you reach the end of the loop:
var i = 1, time = 10, handle;
function timer() {
console.log(i);
i++;
if (i > time) clearInterval(handle);
}
handle = setInterval(timer, 1000);
First, it's not working because setTimeout call is wrong. Even if your setTimeout call worked, there's another issue here. Your code will actually print 11 every 10 seconds.
function timer() {
var time = 10;
for (i = 0; i < time; i++) {
setTimeout(function() {
console.log(i + 1)
}, 1000);
}
}
setInterval(timer, 10000);
Because, you have sequential setTimeout calls to be effected every second and you are forming a closure on the variable i.
You need to take care of the closure and calls must be done after the second has been printed.
function timer() {
var p = Promise.resolve();
for (var i = 0; i < 10; i++) {
p = p.then(closure(i));
}
}
function closure(i) {
return (function () {
return new Promise(function (resolve) {
setTimeout(function () {
document.getElementById('results').innerHTML = (i + 1) + '\n';
resolve();
}, 1000);
})
});
}
timer();
setInterval(timer, 10000);
<pre id="results"></pre>
When I run your code in the Firebug debugger, I see:
TypeError: can't convert console.log(...) to string
I added a comment to your code about that error:
function timer() {
var time=10;
for(i=0; i<time; i++){
// The source of error is the line below
// Type error: setTimeout needs a function as first argument!
setTimeout(console.log(i+1), 1000);
}
}
setInterval(timer, 10000);
A corrected version might be
function timer() {
var time=10;
for(i=0; i<time; i++){
setTimeout(function() { console.log(i+1); }, 1000);
}
}
setInterval(timer, 10000);
However, the above change fixes the type error but not the logic.
You probably wanted to do this:
var counter = 0;
var count = function() {
console.log(++counter);
if (counter >= 10) {
clearInterval(timer);
}
};
var timer = setInterval(count, 1000);
Once the callback function count notices the counter passed the value 10 it will stop the periodic timer whose ID was saved in the variable timer when setting it up.

Javascript: Force new loop iteration in setInterval

I have a setInterval loop. It's set to 3500 milliseconds, like so:-
var loop = setInterval(function() { /*stuff*/ }, 3500);
At one point in 'stuff' if a certain situation occurs, I want to force a new iteration of the loop and NOT WAIT for the 3500 milliseconds. How is that possible? Is it continue or do I just need to frame the process differently?
You could try writing an anonymous self-calling function using setTimeout instead of setInterval:
var i = 0;
(function() {
// stuff
i++;
if (i % 2 == 0) {
// If some condition occurs inside the function, then call itself once again
// immediately
arguments.callee();
} else {
// otherwise call itself in 3 and a half seconds
window.setTimeout(arguments.callee, 3500);
}
})();ā€‹ // <-- call-itself immediately to start the iteration
UPDATE:
Due to a disagreement expressed in the comments section against the usage of arguments.callee, here's how the same could be achieved using a named function:
var i = 0;
var doStuff = function() {
// stuff
i++;
if (i % 2 == 0) {
// If some condition occurs inside the function, then call itself once again
// immediately
doStuff();
} else {
// otherwise call itself in 3 and a half seconds
window.setTimeout(doStuff, 3500);
}
};
doStuff();
You can use something like this... using setTimeout instead of setInterval...
<script type="text/javascript">
var show;
var done = false;
show = setTimeout(showHideForm, 3500);
function showHideForm() {
// Do something
if(done) {
clearTimeout(show);
show = setTimeout(showHideForm, 2000);
}
}
</script>
clearTimeout takes as argument the handle which is returned by setTimeout.
Use a named function and call it when you want.
var loop = setInterval(loopFunc, 3500);
function loopFunc(){
//do something
}
function anticipate(){
clearInterval(loop); //Stop interval
loopFunc(); //Call your function
loop = setInterval(loopFunc, 3500); //Reset the interval if you want
}
My contrived example:
var time = 3500,
loops = 0,
loop;
(function run(){
var wait = time,
dontwait = false;
if (loops++ == 5) {
loops = 0;
dontwait = 1000;
}
console.log('Interval: ', dontwait || wait);
return loop = setTimeout(run, dontwait || wait);
})();ā€‹
http://jsfiddle.net/NX43d/1/
Basically, a self-invoking function looping back on a self-calling function, with (!) shorthand variable switching. Nifty.
function looper(t) {
var loop = setInterval(function() {
document.write(s++);
if (mycondition) { // here is your condition
loopagain(200); // specify the time which new loop will do
loop = window.clearInterval(loop); // clear the first interval
return; // exit from this function!
}
}, t);
}
window.onload = looper(1000); // this will have default setInterval function time ans will start at window load!
function loopagain(t) {
looper(t);
}ā€‹
http://jsfiddle.net/tFCZP/

Greasemonkey delay... setTimeout doesnt work ok

I've been playing around with a site, in which I want to continue clicking a button for i amount of times every interval seconds.
My code is:
clickbidBtn1 = function() {
var bidBtn=document.getElementById("BidButton");
var interval = 15000;
for (var i=3; i>=0; i--){
setTimeout(bidBtn.click(1);,i*interval);
};
I've found out that GM executes all i amount of clicks at the same time, not with the intended delay. is there a way to delay the time of click? Say i wanted the function to click the button every 15 second for i amount of times.
I was thinking of giving it some more variables, and adding one variable in the settimeout code part, which only executes # the click, then comparing increased variables with current ones before going to the next settimeout... but haven't thought it through yet... it seems to be a complicated process for a simple process... :( i wll play around with it a bit
Use setInterval() for this.
One way:
var bidClickTimer = 0;
var numBidClicks = 0;
function clickbidBtn1 ()
{
var interval = 15000;
bidClickTimer = setInterval (function() {BidClick (); }, interval);
}
function BidClick ()
{
numBidClicks++;
if (numBidClicks > 3)
{
clearInterval (bidClickTimer);
bidClickTimer = "";
}
else
{
bidBtn.click (1);
}
}
clickbidBtn1 ();
Alternatively, without using global vars:
function clickbidBtn1 ()
{
var interval = 15000;
this.numBidClicks = 0;
this.bidClickTimer = 0;
this.BidClick = function () {
numBidClicks++;
if (numBidClicks > 3)
{
clearInterval (bidClickTimer);
bidClickTimer = "";
}
else
{
bidBtn.click (1);
}
};
this.bidClickTimer = setInterval (function(thisScope) {thisScope.BidClick (); }, interval, this);
}
clickbidBtn1 ();
Just to explain why your code does not work: You are calling the .click method immediately (putting () after a function name calls the function) and actually passing the return value of that function to setTimeout. The for loop is so fast that everything seem to happen at the same time.
You have to pass a function reference to setTimeout, e.g. an anonymous function:
setTimeout(function() {
bidBtn.click(1);
}, i*interval);

Categories

Resources