0

I am learning about setTimeout and tried to print an array inside a loop with a delay where after each iteration the value at different indexes change.My original array is [1,2,3,4,5]. I want the output to be something like this:

enter image description here

I understand that closures can be used with setTimeout to preserve the value of the parameter until execution like mentioned in these Stack Overflow questions. How to preserve setTimeout parameter value until execution? and setTimeout in for-loop does not print consecutive values

so it tried this

let a = [1,2,3,4,5];

for(let i=0;i<a.length;i++){
  a[i]=7;
  dotimeout(a,i)
}

function dotimeout(a,i){
  setTimeout(function(){
    
    console.log(a)},i*1000)
}

and

let a = [1,2,3,4,5];

for(let i=0;i<a.length;i++){
  a[i] = 7;
  (
    function(b,j){
      setTimeout(()=>{
        console.log(b);
      },j*1000)
    }(a,i)
  );
}

but both gave me the same result:

enter image description here

I know that the array manipulation can be done inside the setTimeout callback to achieve the desired result, but that is not what my query is

So my question is: Why the function wrapping the setTimeout( closures, not sure if that is the correct term) doesn't work, and how to preserve the setTimeout parameter until execution with the array manipulation outside the setTimeout.

  • 1
    There’s only one array object, which gets logged at roughly the same time. Unless you make a copy of the object, it can’t log different objects. – deceze Jun 12 '21 at 09:56
  • 1
    I think you should learn more about Event loop first. SetTimeout will not be executed until for loop execution is finished .That's why it is printing all 7 values. – Bhaskar Joshi Jun 12 '21 at 09:58

2 Answers2

1

Your loop runs from start to finish. In each iteration it sets one of the elements of a to 7, and schedule a callback for later, with setTimeout.

By the time the callbacks start to invoke - all elements of a have already been set to 7.

When you pass a as a variable to your inner function you actually pass a reference to it, so inside, your function still sees the up-to-date a array.

One thing you can do is make a copy of a and pass that:

let a = [1,2,3,4,5];

for(let i=0;i<a.length;i++){
  a[i] = 7;
  let copyOfA = [ ...a ];
  (
    function(b,j){
      setTimeout(()=>{
        console.log(b);
      },j*1000)
    }(copyOfA,i)
  );
}

Though with a copy the inner function is redundant. This would also work:

let a = [1,2,3,4,5];

for(let i=0;i<a.length;i++){
  a[i] = 7;
  let copyOfA = [ ...a ];
  setTimeout(()=>{
    console.log(copyOfA);
  },i*1000)
}
obe
  • 7,378
  • 5
  • 31
  • 40
0

The code did nothing wrong. The solution is just so simple that you put a[i] = 7 inside the setTimeout code block. Javascript has a thing called stack and any event that is inside setTimeout function block is always fired after every event from the function that called that setTimeout, even if the timeout is 0ms. So your a[i] = 7 just doesn't wait any millisecond for setTimeout to finish before running into the next loop, in fact it just do it, then call the dotimeout which will be assigned to the bottom of the call stack.

Yves Ng
  • 69
  • 10