This is because add_row()
is asynchronous. It calls the callback you pass it sometime LATER when the operation finishes. Meanwhile, the for
loop has already finished. One simple solution in ES6, is to use let
with your for
loop. This creates a new and separate i
variable for each run of the loop so when the callback is called sometime LATER, the variable i
for that invocation of the loop is still at it was when the function was started.
If you were to insert some console.log()
statements into your code like this:
var m = 3;
console.log("A");
for (i = 0; i < m; i++) {
console.log("B" + i);
add_row('row-'+(i+1), () => {
console.log("C" + i);
f(i);
})
}
console.log("D");
What you would see in the console is this:
A
B0
B1
B2
D
C0
C1
C2
Notice how "D" comes before any of the "Cx" lines. That shows you how the asynchronous callback is called LATER after your for
loop is done executing.
Please study that and when you fully understand the reasoning for that order, then you will finally understand an asynchronous callback. Technically, the C0, C1 and C2 will be at the end, but could be in any order relative to each other.
Here's how you can use let
for the for
loop to create a separate variable i
for each iteration of the loop so you will still have the appropriate value of i
when the callback is called some time later:
for (let i = 0; i < m; i++) {
add_row('row-'+(i+1), () => f(i))
}
Before ES6, one could fix this by creating an extra closure which creates a new function scoped variable to "remember" the loop index separately for each invocation:
for (var i = 0; i < m; i++) {
(function(index) {
add_row('row-'+(index+1), () => f(index))
})(i);
}