There is a setTimeout
inside the for
loop:
for (var i = 1; i <= 5; i++) { setTimeout(function() { console.log(i); }, i * 1000); }
I want to show the numbers 1
, 2
, 3
, 4
, 5
, but it shows 6
, 6
, 6
, 6
, 6
. Why?
There is a setTimeout
inside the for
loop:
for (var i = 1; i <= 5; i++) { setTimeout(function() { console.log(i); }, i * 1000); }
I want to show the numbers 1
, 2
, 3
, 4
, 5
, but it shows 6
, 6
, 6
, 6
, 6
. Why?
The point is that the function is executed after the cycle ends. Therefore, i
is equal to 6
when console.log(i)
is executed for the first time.
If it is still not clear, here is a similar example in pseudocode:
Π£ ΠΌΠ΅Π½Ρ 1 ΠΊΠ°ΠΌΠ΅Π½Ρ. Π§Π΅ΡΠ΅Π· ΠΌΠΈΠ½ΡΡΡ ΡΠΊΠ°ΠΆΠΈ, ΡΠΊΠΎΠ»ΡΠΊΠΎ Ρ ΠΌΠ΅Π½Ρ ΠΊΠ°ΠΌΠ½Π΅ΠΉ. ΠΠ°ΠΉ ΠΌΠ½Π΅ ΠΊΠ°ΠΌΠ΅Π½Ρ ΡΠ΅ΠΉΡΠ°Ρ. Π§Π΅ΡΠ΅Π· 2 ΠΌΠΈΠ½ΡΡΡ ΡΠΊΠ°ΠΆΠΈ, ΡΠΊΠΎΠ»ΡΠΊΠΎ Ρ ΠΌΠ΅Π½Ρ ΠΊΠ°ΠΌΠ½Π΅ΠΉ. ΠΠ°ΠΉ ΠΌΠ½Π΅ ΠΊΠ°ΠΌΠ΅Π½Ρ ΡΠ΅ΠΉΡΠ°Ρ.
It turns out that now I will give 2 stones, in the end I will have 3. In a minute, he will say how many stones I have (ie, 3), and in two minutes he will say again that I have 3 stones.
i
to the output function at each iteration. This is the most common solution. for(var i = 1; i <= 5; i++) { (function(i) { setTimeout(function() { console.log(i); }, i * 1000); })(i); }
Creating many of the same functions is not very good, you can raise this function above:
function pass(i) { return function () { console.log(i); } } for(var i = 1; i <= 5; i++) { setTimeout(pass(i), i * 1000); }
(function f(i) { if (i > 5) return; setTimeout(function() { console.log(i); f(i + 1); }, 1000); })(1);
Function.prototype.bind()
to create a new function at each iteration. This is shorter than the first option, but IE8 and below do not support .bind
. for (var i = 1; i <= 5; i++) { setTimeout(function(i) { console.log(i); }.bind(null, i), i * 1000); }
setTimeout
. This is supported by all modern browsers, but if we are talking about old ones, then it is worth checking out. for(var i = 1; i <= 5; i++) { setTimeout(function (i) { console.log(i); }, i * 1000, i); }
I note that now the functions in the loop are no different from each other, so you can make one function:
function doSmth(i) { console.log(i); } for(var i = 1; i <= 5; i++) { setTimeout(doSmth, i * 1000, i); }
Use let
. This is a convenient option, but it is a new feature in ECMAScript 2015, so it still does not work in most browsers. If you want to use ECMAScript 2015 to the point that browsers support it, I recommend trying Babel .
Warning: some browsers (for example, IE 11) support let
, but do not support it in the for
loop.
for (let i = 1; i <= 5; i++) { setTimeout(function() { console.log(i); }, i * 1000); }
setInterval
. - Regenti + 1
in setTimeout
. Could you explain? And yes, in this case the setInterval
option is convenient, but I wanted an answer that works in the general case. Maybe instead of setTimeout
, there is an AJAX request or another asynchronous function. - Peter OlsonsetInterval
will work exactly the same. - RegentAsync solution
const intArray = [1, 2, 3, 4, 5]; async.eachSeries(intArray, function(i, callback) { setTimeout(function() { console.log(i); callback(); }, i * 1000); }, function(err) { // if any of the file processing produced an error, err would equal that error if( err ) { console.log('An error occured. All processing has stopped'); } else { console.log('Whole array processed successfully'); } });
<script src="https://cdnjs.cloudflare.com/ajax/libs/async/2.4.0/async.js"></script>
Source: https://ru.stackoverflow.com/questions/961718/
All Articles