We sometimes encounter the problem of calling setTimeout in a loop to iterate over, as shown below.
for (var i = 1; i <= 5; i++) {
setTimeout(function timer() {
console.log(i)
}, i * 1000)
}
The output result will only be 5 6, because JavaScript is single-threaded, executed sequentially, setTimeout is an asynchronous function, it will put the timer function into the task queue, and at this time the loop will be executed before executing the timer function, So when the timer function is executed, i is already equal to 6, so it will eventually output 5 6s, so there are three solutions to make the timer output 1, 2, 3, 4, 5.
the first method is through closures.
for (var i = 1; i <= 5; i++) {
(function(j) {
setTimeout(function timer() {
console.log(j)
}, j * 1000)
})(i)
}
in the above code, we first use the immediate execution function to pass i inside the function, at this time the value is fixed on the parameter j and will not change, and the next time the timer closure is executed, the variable of the external function can be used j , so as to achieve the goal.
The second method is to use the third parameter of setTimeout, and the third and subsequent parameters of setTimeout will be passed in as parameters to the second parameter function, that is, the third and subsequent parameters will be passed in as parameters to timer, so the code is written as follows.
for (var i = 1; i <= 5; i++) {
setTimeout(
function timer(j) {
console.log(j)
},
i * 1000,
i
)
}
the third method is to use es6’s newly added let definition i
to solve the problem, which is also the most recommended method.
for (let i = 1; i <= 5; i++) {
setTimeout(function timer() {
console.log(i)
}, i * 1000)
}