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

问题描述 投票:3回答:3

我试图使用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循环的每次迭代之间有延迟?

javascript async-await
3个回答
1
投票

你理论上可以建立一个承诺链,使用reduce略微更漂亮,但同样的模式也可以用forEach完成:

[0, 1, 2, 3, 4].reduce(async (previous) => {
  await previous;
  console.log('waiting')
  await sleep(1000)
});

但是......为什么不使用for循环呢?


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/[email protected]/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


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);
});
© www.soinside.com 2019 - 2024. All rights reserved.