Reputation: 2048
I want to execute a series of function calls, each of which posts a jGrowl message on the screen. When I do this without a delay, nothing gets shown on the screen. When I try to put a delay inside a timeout loop, all of the calls get executed immediately.
Here is the code:
var tests = [];
tests.push("$.notification('this is a test');");
tests.push("$.notification('this is a test', 7);");
tests.push("$.notification({ message: 'this is a test', code: 'warning', sticky: false });");
tests.push("$.diagnostic({ message: 'click OK to continue', alert: true });");
tests.push("$.notification.erase();");
// WHY DOESN'T THIS WORK?
//>
function wait(ms) {
var done = false;
while (!done) {
setTimeout(function () {
done = true;
}, ms)
}
}
Here is the console:
16.30.6.265: : Executing test[0]: $.notification('this is a test');
16.30.6.266: : Executing test[1]: $.notification('this is a test', 7);
16.30.6.266: : Executing test[2]: $.notification({ message: 'this is a test', code: 'warning', sticky: false });
16.30.6.266: : Executing test[3]: $.diagnostic({ message: 'click OK to continue', alert: true });
16.30.6.266: : Executing test[4]: $.notification.erase()
;
The timestamp is in ms, so there is no delay happening.
Upvotes: 0
Views: 139
Reputation: 27282
The problem is that setTimeout
doesn't "stack". That is, when you call setTimeout
followed by another setTimeout
, JavaScript doesn't execute the first one, THEN execute the second one. It says "oh hey, do these two timeouts some time from now". If that time is the same, then they will both execute at the same time (or within microseconds of each other; nor should you rely on one executing before the other).
There are two solutions to your problem. Either you can increment the timeout each time so that the events will occur in a staggered fashion, or you can chain the timeouts so that the first one triggers the second one, the second one triggers the third one, and so forth.
I think the first approach (incrementing the timeout) will probably produce an easier and cleaner solution, so I'll present that here:
delay = 500; // half a second between messages
for (var i = 0; i < tests.length; i++) {
t = tests[i];
$.diagnostic('Executing test[' + i + ']: ' + t);
(function (index,t) {
setTimeout(function() {
eval(t);
}, index*delay);
})(i,t);
}
As an aside, the use of eval
is highly discouraged: it can only lead to misery and hard-to-maintain code. Better to use anonymous functions; from what I can see of your problem, there's no reason you can't do that.
Upvotes: 1