async/await
is freaking awesome, but there is one place where it’s tricky: inside a forEach()
Let’s try something:
const waitFor = (ms) => new Promise(r => setTimeout(r, ms));[1, 2, 3].forEach(async (num) => { await waitFor(50); console.log(num); });console.log('Done');
If you run this code with node.js (≥ 7.6.0), this will happen:
$ node forEach.js
$ Done
What?
console.log(num)
are not displayed into the console.
Let’s re-create
forEach()
to understand what’s happening:Array.prototype.forEach = function (callback) {
// this represents our array
for (let index = 0; index < this.length; index++) {
// We call the callback for each entry
callback(this[index], index, this);
}
};
The real polyfill of
forEach()
is available at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach#Polyfill
As you can see, the
callback
is called but we are not waiting for it to be done before going to the next entry of the array.
We can solve this by creating our own
asyncForEach()
method:async function asyncForEach(array, callback) {
for (let index = 0; index < array.length; index++) {
await callback(array[index], index, array);
}
}
Then, we can update our example to use our
asyncForEach
method:asyncForEach([1, 2, 3], async (num) => { await waitFor(50); console.log(num); })console.log('Done');
By running this code into node, we can now see:
$ node forEach.js
$ Done
$ 1
$ 2
$ 3
We’re getting closer!
Actually, our
asyncForEach
returns a Promise
(since it’s wrapped into an async
function) but we are not waiting for it to be done before logging ‘Done’.
Let’s update our example again to wrap our execution into an
async
method:const start = async () => { await asyncForEach([1, 2, 3], async (num) => { await waitFor(50); console.log(num); }); console.log('Done'); }start();
Let’s run it one last time:
$ node forEach.js
$ 1
$ 2
$ 3
$ Done
🎉 We now have a way of using
forEach
with async/await
🎉
Comments
Post a Comment