JavaScript中的异步数组循环
异步操作似乎让很多开发者感到困惑。当与数组循环结合时,会有一些注意事项需要注意。
for循环
将async
与for
(或for...of
)循环结合起来可能是执行异步操作的最直接的选项之一。在for
循环中使用await
会导致代码停止并等待异步操作完成后再继续执行。这意味着所有的Promise将按顺序运行。
const asyncUppercase = item =>
new Promise(resolve =>
setTimeout(
() => resolve(item.toUpperCase()),
Math.floor(Math.random() * 1000)
)
);
const uppercaseItems = async () => {
const items = ['a', 'b', 'c'];
for (item of items) {
const uppercaseItem = await asyncUppercase(item);
console.log(uppercaseItem);
}
console.log('Items processed');
};
uppercaseItems();
// 输出: 'A', 'B', 'C', 'Items processed'
Promises
Promise.all()
提供了另一种在数组上进行异步循环的选项。与前面的选项相比,主要区别在于Promise.all()
会并行执行所有的异步操作。这意味着Promise将无序执行,这在某些情况下可能会成为问题。大多数情况下,这是我首选的解决方案,因为很少有需要按顺序执行Promise的情况。
const asyncUppercase = item =>
new Promise(resolve =>
setTimeout(
() => resolve(item.toUpperCase()),
Math.floor(Math.random() * 1000)
)
);
const uppercaseItems = () => {
const items = ['a', 'b', 'c'];
return Promise.all(
items.map(async item => {
const uppercaseItem = await asyncUppercase(item);
console.log(uppercaseItem);
})
).then(() => {
console.log('Items processed');
});
};
// 输出: 'A', 'C', 'B', 'Items processed'
数组方法
不幸的是,Array.prototype.forEach()
等数组方法与 async
/await
不兼容。唯一可行的解决方案是使用 Promise.all()
,如前面的示例所示。使用带有 Array.prototype.forEach()
的 async
回调将导致代码的其余部分执行,而异步操作不会被等待。
const asyncUppercase = item =>
new Promise(resolve =>
setTimeout(
() => resolve(item.toUpperCase()),
Math.floor(Math.random() * 1000)
)
);
const uppercaseItems = async () => {
const items = ['a', 'b', 'c'];
await Promise.all(items.map(async item => {
const uppercaseItem = await asyncUppercase(item);
console.log(uppercaseItem);
}));
console.log('Items processed');
};
uppercaseItems();
// 输出: 'Items processed', 'B', 'A', 'C'