I'm a bit confused as to how setTimeout
works. I'm trying to have a setTimeout
in a loop, so that the loop iterations are, say, 1s apart.
Each loop iteration makes an HTTP request and it seems like the server on the other end can't handle that many requests in such a short time span.
for (var i = 1; i<=2000 && ok; i++) {
var options = {
host:'www.host.com',
path:'/path/'+i
};
setTimeout(makeRequest(options, i), 1000);
};
Why does this not work and how can I achieve this?
Thank you
The setTimeout function callback isn't triggered until the for loop execution has completed. When the for loop has finished executing the value of i is 5. Now when the setTimeout call begins to execute it uses the last set value of i which is 5. Hence 5 is printed in all the setTimeout callbacks.
The setTimeout function is used to call a function after the specified number of milliseconds. The delay of the called function begins after the remaining statements in the script have finished executing. The setTimeout function is found in the Timers module of Node. js.
Event loop is an endless loop, which waits for tasks, executes them and then sleeps until it receives more tasks. The event loop executes tasks from the event queue only when the call stack is empty i.e. there is no ongoing task. The event loop allows us to use callbacks and promises.
setTimeout is non blocking, it is asynchronous. You give it a callback and when the delay is over, your callback is called.
Here are some implementations:
You can use a recursive call in the setTimeout
callback.
function waitAndDo(times) {
if(times < 1) {
return;
}
setTimeout(function() {
// Do something here
console.log('Doing a request');
waitAndDo(times-1);
}, 1000);
}
Here is how to use your function:
waitAndDo(2000); // Do it 2000 times
About stack overflow errors: setTimeout
clear the call stack (see this question) so you don't have to worry about stack overflow on setTimeout
recursive calls.
If you are already using io.js (the "next" Node.js that uses ES6) you can solve your problem without recursion with an elegant solution:
function* waitAndDo(times) {
for(var i=0; i<times; i++) {
// Sleep
yield function(callback) {
setTimeout(callback, 1000);
}
// Do something here
console.log('Doing a request');
}
}
Here is how to use your function (with co):
var co = require('co');
co(function* () {
yield waitAndDo(10);
});
BTW: This is really using a loop ;)
Generator functions documentation.
You need something like this
var counter = 5;
function makeRequst(options, i) {
// do your request here
}
function myFunction() {
alert(counter);
// create options object here
//var options = {
// host:'www.host.com',
// path:'/path/'+counter
//};
//makeRequest(options, counter);
counter--;
if (counter > 0) {
setTimeout(myFunction, 1000);
}
}
See also this fiddle
At the point of the alert(count);
you can do your call to the server.
Note that the counter works opposite (counting down). I updated with some
comments where to do your thing.
Right now you're scheduling all of your requests to happen at the same time, just a second after the script runs. You'll need to do something like the following:
var numRequests = 2000,
cur = 1;
function scheduleRequest() {
if (cur > numRequests) return;
makeRequest({
host: 'www.host.com',
path: '/path/' + cur
}, cur);
cur++;
setTimeout(scheduleRequest, 1000)
}
Note that each subsequent request is only scheduled after the current one completes.
I might be late at the party but here is another (more readable) solution without the need to omit for
loop.
What your code does is creating 2000 (actually 1999) setTimeout
objects that will call the makeRequest
function after 1 second from now. See, none of them knows about the existence of the other setTimeout
s.
If you want them 1 sec apart from each other, you are responsible for creating them so.
This can be achieve by using your counter (in this case i
) and the timeout delay.
for (var i = 1; i<=2000 && ok; i++) {
var options = {
host:'www.host.com',
path:'/path/'+i
};
setTimeout(makeRequest(options, i), i * 1000); //Note i * 1000
};
The first timeout object will be set for 1 second from now and the second one will be set for 2 seconds from now and so on; Meaning 1 second apart from each other.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With