首页 > 解决方案 > while 循环和承诺

问题描述

我试图更好地理解承诺方面的异步行为。我正在尝试使用永远的 while 循环来执行承诺。我已经阅读了几篇关于如何做到这一点的帖子,但我想了解为什么以下内容不起作用。

承诺.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 被调用(如 in 调用promise.then(...).catch(...))更快,然后它们被解决?

是什么导致进程挂起然后用完堆内存?

标签: javascriptpromise

解决方案


考虑这段代码:

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();

因为这使用 async await 语法,所以 while 循环的行为与您的 Promise 不同。如果您通过 webpack/babel 运行它以将其转换为 es5 Promise,您可能会发现它做了一些非常有趣的事情。


推荐阅读