使用递归承诺阻止内存泄漏 [英] Stop memory leaks with recursive promises

查看:141
本文介绍了使用递归承诺阻止内存泄漏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何使用 Q库创建JavaScript Promise的递归链?以下代码无法在Chrome中完成:

How do I create a recursive chain of JavaScript Promises with the Q library? The following code fails to complete in Chrome:

<html>
    <script src="q.js" type="text/javascript"></script>
    <script type="text/javascript">
        //Don't keep track of a promises stack for debugging
        //Reduces memory usage when recursing promises
        Q.longStackJumpLimit = 0;

        function do_stuff(count) {
            if (count==1000000) {
                return;
            }

            if (count%10000 == 0){
                console.log( count );
            }

            return Q.delay(1).then(function() {
                return do_stuff(count+1);
            });
        }

        do_stuff(0)
        .then(function() {
            console.log("Done");
        });
    </script>
</html>

推荐答案

这不会堆栈溢出,因为Promise会破坏堆栈,但会泄漏内存.如果您在node.js中运行相同的代码,则会得到一条错误消息:

This won't stack overflow because promises break the stack, but it will leak memory. If you run this same code in node.js you'll get an error that reads:

FATAL ERROR: CALL_AND_RETRY_2 Allocation failed - process out of memory

这里发生的是,正在创建一个非常长的嵌套承诺链,每个嵌套承诺都在等待下一个.您需要做的是找到一种方法来扁平化该链,以便仅返回一个顶级承诺,等待当前表示某些实际工作的最内在的承诺.

What is happening here is that a really long chain of nested promises is being created, each waiting for the next. What you need to do is find a way to flatten that chain so that there is just one top level promise that gets returned, waiting on the inner most promise that is currently representing some real work.

最简单的解决方案是在顶层构造一个新的promise并使用它来打破递归:

The easiest solution is to construct a new promise at the top level and use it to break the recursion:

var Promise = require('promise');

function delay(timeout) {
    return new Promise(function (resolve) {
        setTimeout(resolve, timeout);
    });
}

function do_stuff(count) {
    return new Promise(function (resolve, reject) {
        function doStuffRecursion(count) {
            if (count==1000000) {
                return resolve();
            }

            if (count%10000 == 0){
                console.log( count );
            }

            delay(1).then(function() {
                doStuffRecursion(count+1);
            }).done(null, reject);
        }
        doStuffRecursion(count);
    });
}

do_stuff(0).then(function() {
    console.log("Done");
});

尽管此解决方案不太理想,但您可以确定它可以在所有promise实现中使用.

Although this solution is somewhat inelegant, you can be sure it will work in all promise implementations.

一些promise实现(例如,npm中的 promise ),您可以将其下载为独立库来自 https://www.promisejs.org/)正确地检测到这种情况并将承诺链分解成一个单一的承诺.如果您不保留对顶级函数返回的诺言的引用(即立即对其调用.then,不要守在它附近),则此方法有效.

Some promise implementations (for example promise from npm, which you can download as a standalone library from https://www.promisejs.org/) correctly detect this case and collapse the chain of promises into a single promise. This works providing you don't keep a reference to the promise returned by the top level function (i.e. call .then on it immediately, don't keep it around).

好:

var Promise = require('promise');

function delay(timeout) {
    return new Promise(function (resolve) {
        setTimeout(resolve, timeout);
    });
}

function do_stuff(count) {
    if (count==1000000) {
        return;
    }

    if (count%10000 == 0){
        console.log( count );
    }

    return delay(1).then(function() {
        return do_stuff(count+1);
    });
}

do_stuff(0).then(function() {
    console.log("Done");
});

坏:

var Promise = require('promise');

function delay(timeout) {
    return new Promise(function (resolve) {
        setTimeout(resolve, timeout);
    });
}

function do_stuff(count) {
    if (count==1000000) {
        return;
    }

    if (count%10000 == 0){
        console.log( count );
    }

    return delay(1).then(function() {
        return do_stuff(count+1);
    });
}

var thisReferenceWillPreventGarbageCollection = do_stuff(0);

thisReferenceWillPreventGarbageCollection.then(function() {
    console.log("Done");
});

不幸的是,内置的promise实现都没有这种优化,也没有实现它的任何计划.

Unfortunately, none of the built in promise implementations have this optimisation, and none have any plans to implement it.

这篇关于使用递归承诺阻止内存泄漏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆