在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很大?
答案 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
示例更方便。