If I'm guessing correctly then this is what you've probably tried:
for (var i = 0; i < 100; i++) {
setTimeout(function() {
$('.class.' + i).children('.BUTTON').click();
}, time * i);
}
It didn't work because of the asynchronous nature of javascript due to which the callback of setTimeout
doesn't get executed immediately. This is good for your purpose, BUT every time you call setTimeout
, its callback is actually referring to the same iterator i
(due to lexical-scoping).
So that when the callbacks are actually executed, each callback now refers to the same i
(with the same value) and, therefore, all the buttons get clicked simultaneously.
This problem can also be attributed to the preference of lexical-scoping
over block-scoping
in javascript. However, we know that a function
in javascript also behaves as a block-scoped construct (in fact it is the only thing in javascript that is block-scoped). So we will use it like this:
for (var i = 0; i < 100; i++) {
(function(i) { // IIFE starts
setTimeout(function() {
$('.class.' + i).children('.BUTTON').click();
}, time * i);
})(i); // <-------IIFE ends
}
What I did here is called an IIFE (Immediately Invoked Function Expression). An IIFE is a function-expression that gets executed immediately when the program control reaches it. And because a function is block-scoped in javascript, the variable i
that is passed to it becomes a member of it's scope (due to pass-by-value) and thus no longer depends on the outer loop's i
.
So basically we've created a new i
within the IIFE
. And for each IIFE
the value of i
is different.
Here's a simple example:
WITH IIFE:
for (var i = 0; i < 100; i++) {
(function(i) { // IIFE starts
setTimeout(function() {
console.log(i); // <----- simply printing the iterator i
}, 500);
})(i); // <-------IIFE ends
}
OUTPUT:
0
1
2
3
... (upto 99)
WITHOUT IIFE:
for (var i = 0; i < 100; i++) {
setTimeout(function() {
console.log(i); // <----- simply printing the iterator i
}, 500);
}
OUTPUT:
100
100
100
... (100 times)