在循环中使用异步等待时,您可能会遇到其中一些问题。
如果您只是尝试在内部使用await forEach,则会抛出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,然后您可以执行以下操作:基本上,您返回一个Promise,它在等待和完成所有回调时解析。但是有更好的方法可以做到这一点,那就是使用循环。await asyncForEach(async (e) => await somePromiseFn(e), data )
您可以使用一个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按顺序执行调用,那么这很好,但是如果您希望它们并发运行,则需要awaiton 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也将被解析。我们await信守这一诺言,当它成为现实时,我们所有的价值观都可以实现。
上面的示例是完全可运行的。该somePromiseFn函数可以作为具有超时的异步回显函数使用。您可以尝试至少使用stage-3预设的babel-repl中的示例,并查看输出。
function somePromiseFn(n) { return new Promise((res, rej) => { setTimeout(() => res(n), 250); }); }