如何在JavaScript中使用async / await延迟数组回调?

时间:2019-04-01 22:59:30

标签: javascript async-await

我正在尝试使用异步等待在循环中的每次迭代之间设置延迟。我有一个辅助睡眠功能:

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循环的每次迭代之间都有延迟?

3 个答案:

答案 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);
});