在javascript中承诺的批处理模式

时间:2017-03-02 10:09:58

标签: javascript promise

我需要处理大量数据。对于数据的每个条目,我们需要向mysql提交查询。我目前的解决方案如下:

    var Q = require('q');
    function process(entry){
        ...
        var defered=Q.defer();
        connection.query(sql,defered.makeNodeResolver());
        return defered.promise;
    }
    function ProcessAll(results ) {
        var waitfor=[];
        for( var i=0;i< results.length;i++){
            waitfor.push( process(results[i]));
        }
        Q.all(waitfor).then(function(results) {
            notifySuc(results);
        },function(results){
            notifyFail(results);
        });
    }

但是,当数据量很大时,由于内存不足会导致数据崩溃:

FATAL ERROR: Committing semi space failed. Allocation failed - process out of memory

 1: node::Abort() [node]
 2: 0x109624c [node]
 3: v8::Utils::ReportApiFailure(char const*, char const*) [node]
 4: v8::internal::V8::FatalProcessOutOfMemory(char const*, bool) [node]
 5: v8::internal::Heap::PerformGarbageCollection(v8::internal::GarbageCollector, v8::GCCallbackFlags) [node]
 6: v8::internal::Heap::CollectGarbage(v8::internal::GarbageCollector, char const*, char const*, v8::GCCallbackFlags) [node]

如何以较小的批次打破它?例如,我们每次可以处理1000个条目。在他们都是我们之后我们恢复其余的。如何使用回调函数?

另外,我们可以并行处理多个条目吗?

2 个答案:

答案 0 :(得分:0)

您可以使用类似BaconJS的内容来执行此操作。您可以使用 Bacon.fromPromise(promise [,abort] [,eventTransformer])创建一个事件流,然后使用 stream.bufferWithCount(count)将您的处理分解为批次。 BaconJS 是一个小型的功能反应式编程库。要了解有关FRP的更多信息,您可以阅读The Introduction to FRP以获得快速入门。

答案 1 :(得分:0)

如果错误不是由notifySuc引起的,您可以按照以下方式轻松处理批次

var Q = require('q');
function process(entry){
    ...
    var defered=Q.defer();
    connection.query(sql,defered.makeNodeResolver());
    return defered.promise;
}
function processBatch(batch) {
    return Q.all(batch.map(item => process(item)));
}
function ProcessAll(results) {
    var batchSize = 1000;
    var pos = 0;
    var promises = Q([]); // initial promise of empty array
    while (pos < results.length) {
        (function(pos) {
            promises = promises.then(result => processBatch(results.slice(pos, batchSize)).then(results => result.concat(results)));
        })(pos);
        pos += batchSize;
    }
    promises.then(function(results) {
        notifySuc(results);
    },function(results){
        notifyFail(results);
    });
}