将许多(> 40,000)原生承诺链接在一起会占用太多内存

时间:2016-10-27 03:30:49

标签: javascript node.js promise

我有一个项目,我需要编写一个函数来按顺序计算几个东西,然后将结果写入SQL DB。不幸的是,我需要重复这个超过40,000次。 我使用node.js并承诺完成此任务,但是在10,000次左右的计算之后程序刚刚死亡的内存使用量几乎达到2GB。我开发了自己的本机promiseEach函数,该函数以数量方式获取数组项并将其与promises链接。

我在这里做错了什么?:

function promiseEach(array,promiseFn){
    return new Promise(function(resolve,reject){
        try {
            var promiseArray = [];
            var json = { array: array, counter: 0 }
            for (var i = 0; i < array.length; i++) { 
                promiseArray.push(promiseFn) 
            }
            promiseArray.reduce(function(preFn,curFn,index,pArray){
                return  preFn
                .then( function(z){ return json.array[json.counter++] })
                .then(curFn)
            }, 
            Promise.resolve(json.array[json.counter]))
            .then(resolve,reject)

        }catch(err){
            console.log("promiseEach ERROR:");
            reject(err)
        }
    })
}

2 个答案:

答案 0 :(得分:6)

好吧,你开始过度复杂的功能 - 从我所知道的,你按顺序为每个数组内容调用promiseFn

以下代码在功能上与您的代码相同

function promiseEach(array, promiseFn) {
    return array.reduce(function(prev, item) {
        return prev.then(function() {
            return promiseFn(item);
        });
    }, Promise.resolve());
}

不保证这会解决实际问题,但

为了完整性,因为您在nodejs中编码,与ES2015中编写的代码相同

let promiseEach = (array, promiseFn) => 
    array.reduce((prev, item) => 
        prev.then(() => 
            promiseFn(item)
        )
    , Promise.resolve());

答案 1 :(得分:3)

发布代码中的两行

    .then( function(z){ return json.array[json.counter++] })
    then(curFn)

似乎表示promseFn将在前一次调用完成的操作完成后使用新参数调用,并且前一次调用的已实现值未在promise链中使用。

在从每个函数返回之前避免创建(39,999左右)中间链式promise的建议是使用promiseFn返回的中间promise来在它们满足时调用promise工厂函数,并返回final承诺只有最后的中间承诺才能实现。

后面的概念代码不包含对reduce的调用,因为没有执行reduce操作:

function promiseEach( array, promiseFn) {
    var resolve, reject;
    var counter = 0;
    var final = new Promise( function( r, j) { resolve = r; reject = j});
    function nextPromise() {
        promiseFn( array[counter++])
        .then( (counter < array.length ? nextPromise : resolve), reject);
    }
    if( array.length) {
        nextPromise();
    }
    else {
        reject( new Error("promiseEach called on empty array"));
    }
    return final;
}

添加了备注:

上面的promiseEach函数在node / js中使用同步和异步promiseFn进行了测试,没有对数据数组的并发更新

  • 同步测试

    function promiseSynch( z) {
        return new Promise( function(resolve,reject){resolve(z);});
    }
    
使用带有1GB内存的Win7 i86笔记本,同时打开浏览器,编辑器和任务管理器,

能够在大约10秒钟内处理一个包含100万(1000,000)条目的数组。内存使用量持平至可用内存的80%左右。

  • 异步测试

    function promiseAsynch( z) {
        var resolve;
        function delayResolve() {
            resolve( z);
        }
        return new Promise( ( r, j)=>{
            resolve = r;
            setTimeout(delayResolve,1);
        });
    }
    

在同一台笔记本电脑上管理了超过20分钟的100,000个条目,同样平板电脑的使用率约为80%。

<强>结论

测试表明,Promise不会因为它们被使用而导致内存泄漏,并且它们应该能够处理将冗长的数组数据顺序传递到promise返回函数中。

这意味着存在内存分配失败或神秘处理中断的其他一些原因,需要在问题完全解决之前找到。作为建议,您可以从搜索与正在使用的DB库相关的内存泄漏问题开始。