There are a few solutions to this.
The easiest to implement (given the code you provided), is to simply put a let
before id in your for loop.
for (let id in idList) { ... }
Since the for...in
loop you are using is asynchronous, it is completing before the inner functions contained within the loop are returning, thus id
will always be whatever it was when the loop finished (in this case, 5).
The reason let
must be used instead of var
is because the let
statement declares a block scope local variable.
let allows you to declare variables that are limited in scope to the block, statement, or expression on which it is used. This is unlike the var keyword, which defines a variable globally, or locally to an entire function regardless of block scope. (source)
So, let
will work, var
(or a global variable, as you have it) will not.
However, it is advised not to use for...in
loops on arrays when the index order is important. (source)
A better solution would be to use the for...of
loop, which, will visit the elements in a consistent order. This is also a fairly simple change of swapping out the word "in" with "of" to create the loop.
for (let id of idList) { ... }
A more declarative solution would be to use the forEach method available on every array created in JavaScript. This is executes a callback function for each element in the array.
const idList = [0, 1, 2, 3, 4, 5];
idList.forEach(id => {
new Promise((resolve, reject) => {
setTimeout(() => resolve(10), 300);
})
.then((num) => {
console.log(id + ': ' + num);
return num * 2;
});
})
However, please note that forEach
will always return undefined, even if you give the callback a return value. That doesn't seem to be a problem in your case here, since all you are looking to do is console.log
the asynchronous values as they come in.