async/await是非常酷的功能,但有一个地方很棘手:在forEach()里面
我们试试看:
const waitFor = (ms) => new Promise(r => setTimeout(r, ms));[1, 2, 3].forEach(async (num) => { await waitFor(50); console.log(num);});console.log('Done');
如果使用node.js(≥7.6.0)运行此代码,则会发生以下情况:
$ node forEach.js$ Done
什么?
console.log(num)不会显示在控制台中。
让我们重新创建forEach()以了解发生了什么:
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); }};
正如您所看到的,调用了回调,但我们并没有等到它在进入数组的下一个条目之前完成。
我们可以通过创建自己的asyncForEach()方法来解决这个问题:
async function asyncForEach(array, callback) { for (let index = 0; index < array.length; index++) { await callback(array[index], index, array); }}
然后,我们可以更新我们的示例以使用我们的asyncForEach方法:
asyncForEach([1, 2, 3], async (num) => { await waitFor(50); console.log(num);})console.log('Done');
通过将此代码运行到节点中,我们现在可以看到:
$ node forEach.js$ Done$ 1$ 2$ 3
实际上,我们的asyncForEach返回一个Promise(因为它包含在一个异步函数中),但是我们不会在记录'Done'之前等待它完成。
让我们再次更新我们的示例,将执行包装成异步方法:
const start = async () => { await asyncForEach([1, 2, 3], async (num) => { await waitFor(50); console.log(num); }); console.log('Done');}start();
我们最后一次运行它:
$ node forEach.js$ 1$ 2$ 3$ Done
我们现在有一种方法可以使用forEach和async/await