我正在尝试使用异步等待在循环中的每次迭代之间设置延迟。我有一个辅助睡眠功能:
const sleep = ms => {
return new Promise(resolve => {
setTimeout(resolve, ms);
});
}
这在每个循环之间正确等待:
for (let i = 0; i < 5; i++) {
console.log('waiting')
await sleep(1000)
}
但是,这并不是在每个循环之间都等待:
[0, 1, 2, 3, 4].forEach(async () => {
console.log('waiting')
await sleep(1000)
});
如何修改forEach代码块,使其表现为常规的for循环块,而for循环的每次迭代之间都有延迟?
答案 0 :(得分:1)
您理论上可以建立起一个承诺链,reduce
可以使它更美丽,但是forEach
也可以实现相同的模式:
[0, 1, 2, 3, 4].reduce(async (previous) => {
await previous;
console.log('waiting')
await sleep(1000)
});
但是...为什么不只使用for
循环?
答案 1 :(得分:1)
如果您更喜欢方法而不是循环(我通常通常只是从美学角度考虑),则可以引入一个我维护的第三方模块async-af
。
除其他事项外,它还提供了asynchronous-friendly sequential forEach:
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
AsyncAF([0, 1, 2, 3, 4]).series.forEach(async () => {
console.log('waiting');
await sleep(1000);
});
<script src="https://unpkg.com/async-af@7.0.14/index.js"></script>
当然,您也可以只使用一个简单的for...of
循环:
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
(async () => {
for (const _ of [0, 1, 2, 3, 4]) {
console.log('waiting');
await sleep(1000);
}
})();
关于为什么 Array.prototype.forEach
不能按您期望的方式工作,请采用这种过于简化的实现(here's a fuller one):
const forEach = (arr, fn) => {
for (let i = 0; i < arr.length; i++) {
// nothing is awaiting this function call
fn(arr[i], i, arr);
// i is then synchronously incremented and the next function is called
}
// return undefined
};
forEach([0, 1, 2, 3, 4], async () => {
console.log('waiting');
await delay(1000);
});
如您所见,Array.prototype.forEach
在每个元素上同步调用给定的回调函数。这就是为什么您几乎立即看到所有五个waiting
日志的原因。有关更多信息,请参见this question。
答案 2 :(得分:1)
首先,for...of
是必经之路。
但是,如果您想.forEach
来死去活,则可以执行以下操作:
const sleep = ms => {
return new Promise(resolve => {
setTimeout(resolve, ms);
});
}
/* Create your own async forEach */
Array.prototype.asyncForEach = async function asyncForEach(callback, ctx){
const len = this.length;
for (let i = 0; i < len; i++)
await callback.call(ctx, this[i], i, this);
};
[0, 1, 2, 3, 4].asyncForEach(async function(n){
await sleep(1000);
console.log(n);
});