while循环和承诺

时间:2019-05-31 15:19:11

标签: javascript promise

我正在尝试根据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(...)中被调用)要比其兑现的速度更快?

是什么导致进程挂起,然后耗尽堆内存?

1 个答案:

答案 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,您可能会发现它做的事情很有趣。