循环使用异步等待
在循环中使用 async await 时,你可能会遇到其中一些问题。
如果你只是尝试在 forEach
中使用 await,这将抛出 Unexpected token
错误。
(async() => {
data = [1, 2, 3, 4, 5];
data.forEach(e => {
const i = await somePromiseFn(e);
console.log(i);
});
})();
这是因为你错误地将箭头函数视为一个块。await
将在回调函数的上下文中,而不是 async
。
解释器保护我们不会出现上述错误,但是如果你将 async
添加到 forEach
回调中,则不会抛出任何错误。你可能认为这解决了问题,但它无法按预期工作。
例:
(async() => {
data = [1, 2, 3, 4, 5];
data.forEach(async(e) => {
const i = await somePromiseFn(e);
console.log(i);
});
console.log('this will print first');
})();
发生这种情况是因为回调异步函数只能暂停,而不是父异步函数。
你可以编写一个 asyncForEach 函数来返回一个 promise,然后你可以像
await asyncForEach(async (e) => await
somePromiseFn(e), data )
那样基本上你会返回一个在等待和完成所有回调时解析的 promise。但是有更好的方法可以做到这一点,那就是使用循环。
你可以使用 for-of
循环或 for/while
循环,你选择哪一个并不重要。
(async() => {
data = [1, 2, 3, 4, 5];
for (let e of data) {
const i = await somePromiseFn(e);
console.log(i);
}
console.log('this will print last');
})();
但还有另一个问题。此解决方案将等待每次调用 somePromiseFn
完成,然后再迭代下一个。
如果你真的希望按顺序执行 somePromiseFn
调用,但是如果你希望它们同时运行,则需要在 Promise.all
上进行此操作。
(async() => {
data = [1, 2, 3, 4, 5];
const p = await Promise.all(data.map(async(e) => await somePromiseFn(e)));
console.log(...p);
})();
Promise.all
接收一个 promises 数组作为其唯一参数并返回一个 promise。当解析数组中的所有 promise 时,也会解析返回的 promise。我们知道这个承诺,当它解决了我们所有的值。
以上示例是完全可运行的。somePromiseFn
函数可以作为具有超时的异步回显函数。你可以尝试使用至少 stage-3
预设的 babel-repl 中的示例并查看输出。
function somePromiseFn(n) {
return new Promise((res, rej) => {
setTimeout(() => res(n), 250);
});
}