1

I am iterating an array iterator using for..of and trying to log the value at a regular interval. My understanding is let keyword will create new variable in each iteration(updated after mistake pointed by VLAZ in comment section) and inside the setIterval it will get a new value. Instead of this , the log inside the setInterval is printing an inconsistent result which I am not able to understand the cause. Will appreciate if you can help to understand this.

Edit: I am aware setTimeout will log a consistent result , but I intended to know why setInterval is logging two result simultaneously and how it is deciding the values

const numbers = [1, 2, 3, 4, 5];
for (let [i, v] of numbers.entries()) {
  setInterval(() => {
    console.log('Output - ', v)
  }, 2000 * (i + 1))
}
brk
  • 48,835
  • 10
  • 56
  • 78
  • 4
    You are setting a new interval in each iteration of the loop. Did you mean to use `setTimeout`? – Yousaf Jul 01 '21 at 06:30
  • "*My understanding is let keyword will create a closure and inside the setIterval*". No, wrong terminology. `let` will create a *new* variable for each iteration. A closure is basically any function. Including the one given to `setInterval`. If you used `var` the callback would still be a closure but there would only be one set of `i` and `v` variables, so when the function executes it will read them and there would be a single value for each single variable. With `let` there are *many* variables called `i` and `v`. Imagine you just have `i0`, `i1`, `i2`, `i3`, `i4` - totally separate. – VLAZ Jul 01 '21 at 06:37
  • "*I intended to know why setInterval is logging two result simultaneously and how it is deciding the values*" The interval you launched when `v =1` will only log `Output - 1`. Nothing else. The interval you launch when `v = 2` will only log `Output - 2`. Nothing else. You just have a bunch of intervals running. – VLAZ Jul 01 '21 at 06:39
  • @VLAZ apologies for that mistake – brk Jul 01 '21 at 06:39
  • @VLAZ do you mind adding this as answer. I can accept it – brk Jul 01 '21 at 06:41

3 Answers3

1

Problem in your code is setting of multiple intervals - each iteration of the loop is setting a new interval which closes over a different value of i and each interval fires after a different time delay.

Each time interval callback is called, it logs the value it closed over when it was initially set up.

In your code, total of 5 intervals are setup and they fire at different times because of the specified time delay: 2000 * (i + 1).

I am aware setTimeout will log a consistent result , but I intended to know why setInterval is logging two result simultaneously

That's because the interval which logs value 1 is fired multiple times before the interval that logs a larger value, for example 5 and that's simply because of the specified time delay: 2000 * (i + 1).

In the first iteration, value of i is 1 and the interval delay will be 2000 * (1 + 1).

Similarly, in the last iteration, value of i is 5 and the interval delay will be 2000 * (5 + 1).

As the delay for the interval set in the first iteration is larger, interval set in the first iteration will fire more than once before the interval set in the fifth iteration.

Use the same time delay for each interval to see the expected results.

Yousaf
  • 27,861
  • 6
  • 44
  • 69
1

The interval you launched when v = 1 will only log "Output - 1". Nothing else.

The interval you launch when v = 2 will only log "Output - 2". Nothing else.

Etc.

You just have a bunch of intervals running. Your code is essentially the same as:

setInterval(() => { 
  console.log('Output - 1')
}, 2000 * 1);

setInterval(() => { 
  console.log('Output - 2')
}, 2000 * 2);

setInterval(() => { 
  console.log('Output - 3')
}, 2000 * 3);

setInterval(() => { 
  console.log('Output - 4')
}, 2000 * 4);

setInterval(() => { 
  console.log('Output - 5')
}, 2000 * 5);

There is nothing about iterators that affects it. Only let matters because it creates separate variables each loop. For more explanation see:

JavaScript closure inside loops – simple practical example
Javascript infamous Loop issue?

If you had used var, then there would be only one i and one v variable. So, your code would effectively be:

setInterval(() => { 
  console.log('Output - 5')
}, 2000 * 1);

setInterval(() => { 
  console.log('Output - 5')
}, 2000 * 2);

setInterval(() => { 
  console.log('Output - 5')
}, 2000 * 3);

setInterval(() => { 
  console.log('Output - 5')
}, 2000 * 4);

setInterval(() => { 
  console.log('Output - 5')
}, 2000 * 5);

This is because when calling setInterval, the time argument 2000 * (i + 1) is based on i would be calculated with the value of i for the current iteration. However, by the time the delayed callback fires, console.log('Output - ', v) would only read the last value of v.

VLAZ
  • 26,331
  • 9
  • 49
  • 67
0

replace setInterval with setTimeout.

const numbers = [1, 2, 3, 4, 5];
for (let [i, v] of numbers.entries()) {
  setTimeout(() => {
    console.log('Output - ', v)
  }, 2000 * (i + 1))
}

You can learn more about it here: setTimeout or setInterval?

ahsan
  • 1,409
  • 8
  • 11