我正在尝试根据Promise更好地理解异步行为。我试图使用一个while循环来执行一个Promise。我已经阅读了有关如何执行此操作的几篇文章,但是我想了解为什么以下内容不起作用。
promises.js
const promise = new Promise(function (resolve, reject) {
resolve('success');
reject('failed');
});
while (true) {
promise.then((res) => {
console.log(res);
}).catch((err) => {
console.log(err);
});
}
预期:
$ node promises.js
success
success
success
success
...
这里...
表示永远持续。
实际:
$ node promises.js
FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory
1: 00007FF7E2D7F04A v8::internal::GCIdleTimeHandler::GCIdleTimeHandler+5114
2: 00007FF7E2D5A0C6 node::MakeCallback+4518
3: 00007FF7E2D5AA30 node_module_register+2032
4: 00007FF7E2FE20EE v8::internal::FatalProcessOutOfMemory+846
5: 00007FF7E2FE201F v8::internal::FatalProcessOutOfMemory+639
6: 00007FF7E3502BC4 v8::internal::Heap::MaxHeapGrowingFactor+9556
7: 00007FF7E34F9C46 v8::internal::ScavengeJob::operator=+24310
8: 00007FF7E34F829C v8::internal::ScavengeJob::operator=+17740
9: 00007FF7E3500F87 v8::internal::Heap::MaxHeapGrowingFactor+2327
10: 00007FF7E3501006 v8::internal::Heap::MaxHeapGrowingFactor+2454
11: 00007FF7E30BCDB7 v8::internal::Factory::NewFillerObject+55
12: 00007FF7E3152CC6 v8::internal::WasmJs::Install+29414
13: 000001BD351DC5C1
在这里,过程只是挂起,然后出现错误。
我的理解是,由于Promise是异步的,因此使用标准的while循环不起作用。我的猜测是,诺言的兑现速度(在promise.then(...).catch(...)
中被调用)要比其兑现的速度更快?
是什么导致进程挂起,然后耗尽堆内存?
答案 0 :(得分:4)
考虑以下这段代码:
const promise = new Promise(function (resolve, reject) {
resolve('success');
reject('failed');
});
var x = 0
while (x < 50) {
promise.then((res) => {
console.log(res);
}).catch((err) => {
console.log(err);
});
x++;
}
就像您一样,但是它只运行while循环50次。如果您在chrome中运行并设置断点,您会发现首先将promise
变量实例化到新的Promise,然后启动while循环,运行promise.then..
的行,然后...
然后您期望接下来发生的事情可能是.then
内部的函数将运行,但是由于promise的异步性质和while
的同步性质,它不会运行到x++
,然后再回到promise.then...
,而无需运行内部函数
内部函数已安排运行 ,但是如果同步javascript永不停止运行,则永远不会有运行的机会。 Javascript是单线程的,因此您的循环版本将永远持续下去,并进行更多的.then
调用,从而填充了堆栈和内存,并中断了操作。
在我的代码中,.then(
中的函数在x = 50之后运行,因为那是while循环停止同步运行的时候。
编辑
还要考虑以下这段代码:
var x = true;
function changeX(count) {
return new Promise(resolve => {
console.log('inside changeX');
setTimeout(function() {
if (count > 10) x = false;
resolve();
},100);
})
}
async function run() {
var count = 0;
while(x) {
await changeX(count);
count++;
}
console.log('x is false now');
}
run();
因为它使用了异步await语法,所以while循环的行为与您的promise不同。如果通过webpack / babel运行此程序以将其转换为es5 promise,您可能会发现它做的事情很有趣。