Passing an array as a function argument to a setTimeout value does not mean passing a variable

The following code uses a for loop to add values ​​to an array. Every time the current state of the array is logged to the console. The setTimeout function is then used to create a half second delay between outputs.

But the delayed output always shows the entire array with status after it has passed the whole for loop, not with status when setTimeout is called.

var my_array = [];

for (var i = 0; i < 10; i++){
  my_array[i] = "Nr " + i;

  console.log(my_array);    
  setTimeout(function(par) { console.log(par); }, 500*i, my_array);

}

      

How can this behavior be explained? Consider the following code, which differs in that it sends an i-variable to the callback (instead of an array):

for (var i = 0; i < 10; i++){

  console.log(i);
  setTimeout(function(par) { console.log(par); }, 500*i, i);

}

      

This snippet writes the i-variable in delayed output with its value at the time setTimeout was called. As expected, it does not register the i-variable with the value it has after the for loop.

+4


source to share


4 answers


At a half-second delay, the original pattern changes so that the hole pattern is displayed. You must clone the array for the desired effect.

Try to change

setTimeout(...); 

      

to

(function (arr) {
    setTimeout(function(par) { console.log(par); }, 500*i, arr);
})(my.slice(0));

      



With my.slice (0), you are cloning the entire array with the current state, so there won't be any changes to it

Update:

setTimeout(function(par) { console.log(par); }, 500, my_array.slice(0));

      

removed * i (you wanted half the delay) and removed the closure (unnecessary). Still works great: https://jsfiddle.net/wuL3a52x/

+2


source


Try the following:



<script>
  var my = [];
  for(var i = 0; i < 10; i++)
  {
    my.push("Nr " + i);
    var myArr=my.slice(0);
    setTimeout(function(x)
    {
      return function()
      {
        console.log(x);
      };
    }(myArr), 1000 * i);
  }
</script>

      

0


source


This is because it setTimeout

uses a reference to my

, and by the time the first callback completes, the loop has already ended.

You can use slice

to create a copy of the array every loop to make it immutable and pass it to setTimeout

var my = [1,2,3,4,5,6,7,8,9,10];

for (var i = 0; i < 10; i++){
  my[i] = "Nr " + i;

  setTimeout(function(par) { console.log(par); }, 500*i, my.slice());

}
      

Run code


0


source


You can solve this with async / await:

 function timer(ms) {
     return new Promise(res => setTimeout(res, ms));
 }

 for (var i = 0; i < myArray.length; i++){
     console.log(myArray[i]);
     await timer(500);
 }

      

0


source