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

时间:2017-12-28 20:45:30

标签: javascript node.js for-loop async-await settimeout

Async/Await之前,当我们需要每隔 X 秒重复一次 N 时,我们可以在包裹{{1}的for循环之间做出选择或者使用settimeout周围的包装来计算它被执行的次数并清除它。

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

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); }); } 实际上并没有在循环中“暂停”,但实际上在迭代时调用10 oldFashion(),所以基本上他用10 setTimeout()填充事件循环。

然而

setTimeout()表现应该是这样,当他等待时,他“停止”迭代,但我不确定那是怎么回事。

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

  

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

2 个答案:

答案 0 :(得分: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 :(得分:1)

  

在newFashion()中实际发生了什么?

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

  

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

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