可以在for循环中等待setTimeout吗?

问题描述 投票:1回答:2

直到Async/Await,当我们需要每隔X秒做一次经常性的N次时,我们可以在包裹settimeout的for循环之间做出选择,或者在setinterval周围使用包装来计算它执行的次数并清除它。

但是使用异步等待是可以的:

async function newFashion() {
  for (let i = 0; i < 10; i++) {
    console.log(i);
    await sleep(1000);
  }
  console.log("Finish"); 
}
newFashion(); // 0 1 2 3 4 5 6 7 8 9 Finish

function oldFashion() {
  for (let i = 0; i < 10; i++) {
    setTimeout(() => {
      console.log(i);
    }, i * 1000);
  }
  console.log("Finish");
}
oldFashion(); // Finish 0 1 2 3 4 5 6 7 8 9

function sleep(time) {
  return new Promise((resolve) => { 
    setTimeout(resolve, time);
  });
}

我知道两者的行为不一样。 oldFashion()实际上并没有在循环中“暂停”,但实际上在迭代时调用10 setTimeout(),所以基本上他用10 setTimeout()填充事件循环。

然而,newFashion()表现得应该如此,他在等待时“停止”迭代,但我不确定那是怎么回事。

那么更好的是,用N setTimeout()填充事件循环,或者一个接一个地等待?在newFashion()实际发生了什么?

编辑:更具体一点,每种方法在性能方面的收益是多少?当N很小?当N很大?

javascript node.js for-loop async-await settimeout
2个回答
2
投票

这是编写“老式”版本的更好方法。它保留了"Finish"日志最后的理想行为,并且它不依赖于将来在不同的时间间隔立即设置一系列定时器。

整个事情是自成一体的,清晰的。

function betterOldFashion(i, n) {
  if (i < n) {
    console.log(i);
    setTimeout(betterOldFashion, 1000, i+1, n);
  } else {
    console.log("Finish");
  }
}
betterOldFashion(0, 10);

您建议的“老式”方式看起来不太可读,因为您没有将行为的一部分抽象为单独的函数,就像您使用“新”方式一样,出于某种原因,您将其置于“老式”方式之下。

为了给出两者相同的好处,这里重写了你的方式,尽管首先不使用命令式循环结构更好,IMO。

function oldFashion() {
  for (let i = 0; i < 10; i++) {
    schedule(i, i);
  }
  schedule("Finish", 10);
}
oldFashion();

function schedule(msg, i) {
  setTimeout(() => {
    console.log(msg);
  }, i * 1000);
}

WRT性能,通常不太关心异步代码,很难衡量。顶部的解决方案当然具有最低的复杂性,如果这是效率的任何指标,并且您的旧方法版本必须立即安排许多事情,创建更多的后台工作。


1
投票

而newFashion()实际上发生了什么?

await表达式导致newFashion函数的调用暂停,直到sleep函数的结果(即Promise)将被解析或拒绝。在解析或拒绝之后,它将继续执行代码的其余部分。

那么更好的是,用N setTimeout()填充事件循环,或者一个接一个地等待?

如您所见,async/await部分更具可读性。如果环境支持ES8,您可以自由使用它。 async/await部分也是熟悉的程序员,他们使用C#等语言进入Javascript,它也使用async/await进行异步编程。对他们来说,使用async/await代替你拥有的for loop例子更方便。

© www.soinside.com 2019 - 2024. All rights reserved.