Javascript function setTimeout and setIntervall not working - javascript

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.

Related

how to stop the setTimeout recursion

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);
}

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! :)

Combine for loop with timing events in javascript

I have this code:
for (i = 0; i < 3; i++) {
var interval = setInterval(function(){
alert(i);
}, 2000);
}
What I would like to achieve is to have an alert every 2 sec displaying first 0, then 1 and lastly 2.
Instead I have to wait for quite long before I have 3 alerts all displaying the number 3. Where is my code wrong?
Well, there is (yet again) more than one solution to this problem. But, lets first talk why your code doesn't work properly.
Your code:
for (i = 0; i < 3; i++) {
var interval = setInterval(function(){
alert(i);
}, 2000);
}
..basically means that it will assign three setInterval calls to be executed after 2 seconds as fast as the for loop is placing them to the queue. So basically, all your calls runs really fast after 2 seconds, only few milliseconds or less between them. Moreover, setInterval means that it will be called as long as clearInterval is called to the variable it is assigned with. In other words, your code never stops executing the alert, because you are never calling clearInterval. Finally, your alert(i) will always display value of 3, because it is the last value of i when execution moves away from the for loop.
To improve your code, you could remove the for loop entirely and just let setInterval run as long as the value of i is alerted three times; At that point, you just call clearInterval to the value which has handle to setInterval and the job is finished.
Working code:
// value to output
var i = 0,
// starting setInterval and assigning its handle to variable interval,
// it is used to clear the interval when execution should be finished
interval = setInterval(function () {
// alert value of i and increase it by 1
alert(i++);
// if i is equals to 3, no more calls
if(i === 3) {
// clear the interval so method won't be called in the future
clearInterval(interval);
}
}, 2000);
JS FIDDLE EXAMPLE
Cheers, hopefully you learnt something new today.
Without forloop:
var number = 0;
var interval = setInterval(function(){
alert(number);
number++;
if(number === 3) {
clearInterval(interval);
}
}, 2000);
JSFIDDLE
1.1 Without for loop + without initial delay (demo):
var i = 0;
var showAlert = function(){
alert(i);
i++;
if(i < 3){
setTimeout(function(){
showAlert();
}, 2000);
}
};
showAlert();
1.2 Without for loop + with initial delay (demo):
var i = 0;
var showAlert = function(){
if(i < 3){
setTimeout(function(){
alert(i);
i++;
showAlert();
}, 2000);
}
};
showAlert();
2.1 With for loop + without initial delay (demo):
function setAlert(k){
setTimeout(function(){
alert(k);
},k * 2000);
}
for(var i = 0; i < 3; i++) {
setAlert(i);
}
2.2 With for loop + with initial delay (demo):
function setAlert(k){
setTimeout(function(){
alert(k);
},(k + 1) * 2000);
}
for(var i = 0; i < 3; i++) {
setAlert(i);
}
First of all, I would go with setTimout, you know that you want 3 alerts.
Second problem is a bit stranger. You are calling async function, setTimeout/setInterval and referring to the original i of the for loop inside of the setTimeout callback. That will not work because at the time of the timeout invocation the for loop has already finished and i var will be 3. One solution is to wrapp the async function in a self invoking anonymous function with params that you need inside async function. In our case we call it with i.
Solution:
for (i = 0; i < 3; i++) {
(function(i) {
setTimeout(function(){
alert(i);
}, 2000 * i);
})(i);
}
JS fiddle

Change millisec for window.setInterval function

I used window.setInterval function. this function includes 3 arguments :
setInterval(code,millisec,lang)
I used that like this:
var counter = 1;
window.setInterval(function() {}, 1000 * ++counter);
but when first time set timer (second argument), is not changed and that act Like below code:
window.setInterval(function() {}, 1000);
please write correct code for change timer
Use window.setTimeout instead.
var delay = 1000;
function myTimer() {
// do whatever
window.setTimeout(myTimer, delay);
}
window.setTimeout(myTimer, delay);
You can manipulate delay in the body of your function.
Your problem is that javascript first execute '1000 * ++counter' once and then do not update the time interval.
You should try to use a timeout instead: https://developer.mozilla.org/en/DOM/window.setTimeout
And create a new time out with the new value every time your time out function is called.
Sounds like what you're after is not setInterval but rather setTimeout in a loop:
var counter = 1;
for (var i = 1; i <= 3; i++) {
window.setTimeout(function() {
alert("#" + counter);
counter++;
}, i * 1000);
}
This will execute three different "timers" one after the other.
Live test case: http://jsfiddle.net/86DRd/

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