当>>> git cherry-pick xyz
fatal: bad object xyz
在await
上时,我有三个摘要循环了三遍。
在第一个代码段中,它按我的预期工作,并且promise
的值随每个i
递减。
await
输出:
let i = 3;
(async () => {
while (i) {
await Promise.resolve();
console.log(i);
i--;
}
})();
在第二个中,3
2
1
的值连续递减,直到达到零,然后执行所有i
。
await
输出:
let i = 3;
while (i) {
(async () => {
await Promise.resolve();
console.log(i);
})();
i--;
}
最后,此错误会导致0
0
0
错误,并且不会显示任何值。
Allocation failed - JavaScript heap out of memory
有人可以解释为什么他们表现出这些不同的行为吗?谢谢。
答案 0 :(得分:16)
关于第二个片段:
在不等待结果的情况下调用异步函数称为即发即弃。您告诉JavaScript它应该开始一些异步处理,但是您不在乎它何时以及如何完成。就是这样它循环,触发一些异步任务,当循环完成时,它们会在完成时返回,并在循环已经结束时记录为0。如果愿意:
await (async () => {
await Promise.resolve();
console.log(i);
})();
它将按顺序循环。
关于您的第三个片段:
您永远不会在循环中减少i
,因此循环将永远运行。如果异步任务在某个时间执行,则会减少i
,但这不会发生,因为while循环会疯狂运行并阻塞浏览器并使之崩溃。
let i = 3;
while(i > 0) {
doStuff();
}
答案 1 :(得分:9)
主要关注最后一个示例:
let i = 3;
while (i) {
(async () => {
await Promise.resolve();
console.log(i);
i--;
})();
}
如果我们在不进行异步/等待的情况下重写代码以揭示其实际功能,则可能会有所帮助。在后台,异步功能的代码执行推迟到以后:
let callbacks = [];
let i = 0;
while (i > 0) {
callbacks.push(() => {
console.log(i);
i--;
});
}
callbacks.forEach(cb => {
cb();
});
如您所见,直到循环完成后,才执行任何回调。由于循环永远不会停止,因此最终虚拟机将用光空间来存储回调。
答案 2 :(得分:2)
在您的特定示例中,它递减i
,然后运行async
代码,如:
let i = 3;
while (i) {
i--; // <---------------------
(async () => { // |
await Promise.resolve();// |
console.log(i); // |
})(); // |
// >---------------------------
}
关于您的第三个代码段,它将永远不会降低i
的值,因此循环将永远运行并因此导致应用程序崩溃:
let i = 3;
while (i) {
(async () => {
await Promise.resolve(); // await and resolve >-----------
// the following code doesn't run after it resolves // |
console.log(i); // |
i--; // |
})(); // |
// out from the (async() => {})() <-------------------------
}
答案 3 :(得分:2)
因为在第一种情况下,console.log和decre相互同步工作,因为它们都在同一个异步函数中。
在第二种情况下,console.log异步工作,而递减工作同步。
因此,递减将首先执行,异步函数将等待同步函数完成,然后使用i == 0
在第三种情况下,循环体同步执行,并在每次迭代时运行异步功能。因此,递减直到循环结束才起作用,因此循环中的条件始终为真。这样,直到堆栈或内存已满