如何将函数调用推送到数组而不在Node JS中调用它们来使用Q?

时间:2017-01-28 11:41:05

标签: arrays node.js dynamic promise q

我希望创建一个动态调用的函数数组,稍后将在Q.all([])promise调用中使用。

例如;

 //data is previously generated

 var promiseArray = [];
 for (var i = 0; i < data.length; i++){     
   promiseArray.push(functionCall(data[i]))
 }
 Q.all(promiseArray).then(function(){
      //Do something 
 })

在Q.all语句之前,如何在不调用函数的情况下推送到数组?我不想在for循环中调用它,因为它不会捕获任何错误,我无法进一步处理响应。

编辑:

所以为了澄清我的问题(因为我认为我没有像我应该的那样清晰),这里有一个静态数据长度为3的解决方案;

//data is previously generated
var data = [12432432,4324322392,433324323];

//Each function call can happen in parallel or series as its an external POST to an API
//I'm not bothered about speed for this application (as its low throughput) and can wait a few seconds for each
// response
//FunctionCall returns a promise

functionCall(data[0]).then(function(){
    //Log success / failure to mongo
});
functionCall(data[1]).then(function(){
    //Log success / failure to mongo
});
functionCall(data[2]).then(function(){
    //Log success / failure to mongo
});

//OR
functionCall(data[0]).then(function(){
    //Log success/failure to mongo
    functionCall(data[1]).then(function(){
        //Log success/failure to mongo
        functionCall(data[2]).then(function(){
            //Log success/failure to mongo
        });
    });
});

但是直到运行时我才知道数据的长度

2 个答案:

答案 0 :(得分:1)

如果我理解正确,您希望为functionCall调用一系列项目,并且functionCall返回的所有承诺已完成后,Q.all会解析如果他们解决或拒绝 - 如果你不关心结果(因为你的代码中似乎没有),只需处理你推动的承诺中的拒绝 - 即

var promiseArray = [];
for (var i = 0; i < data.length; i++) {
    promiseArray.push(functionCall(data[i]).then(function(result) {
        // log success
        return logToMongoFunction(result);
    }, function(error) {
        // log failure
        return logToMongoFunction(error);
    }).catch(function(error) {
        // catch and ignore any error thrown in either logToMongoFunction above
        return;
    }));
}
Q.all(promiseArray).then(function () {
    //Do something 
});
  

注意:以上内容可以简化为

Q.all(data.map(function (item) {
    return functionCall(item).then(function(result) {
        // log success
        return logToMongoFunction(result);
    }, function(error) {
        // log failure
        return logToMongoFunction(error);
    }).catch(function(error) {
        // catch and ignore any error thrown in either logToMongoFunction above
        return;
    });
})).then(function() {
    //Do something 
});
  

编辑过的问题建议您也可以按顺序执行这些操作 - 这将是

data.reduce(function(promise, item) {
    return promise.then(function() {
        return functionCall(item).then(function(result) {
            // log success
            return logToMongoFunction(result);
        }, function(error) {
            // log failure
            return logToMongoFunction(error);
        }).catch(function(error) {
            // catch and ignore any error thrown in either logToMongoFunction above
            return;
        });
    });
}, Promise.resolve()).then(function() {
    // all done
});

而不是Promise.resolve()您可以使用Q所拥有的任何内容作为创建已解决承诺的等价物

logToMongoFunction会记录到mongo并需要返回一个承诺如果你需要等待它完成才能处理下一个数据项。如果您不需要等待mongo日志记录完成,那么该函数不需要返回一个promise

答案 1 :(得分:0)

我建议使用Promise.mapSeries或async库,因为它很容易捕获错误。如果在回调中有数据库调用,那么使用for循环循环的另一件事似乎不是好方法,因为这可能会刷新对数据库的调用,而node.js可能会出现内存问题,或者node.js无法接受任何其他请求,因为它将忙于在for循环中娱乐请求。所以它总是很好地连续运行循环或一次限制并行执行的数量。

请参阅下面的示例

  This will run Array serially one at a time when 1st one completes execution next will be called

  async.eachOfSeries(data, function(dataInstance, key, next) {
    functionCall(dataInstance).then(function(){
        next();
    }).catch(funtion(err){
        next(err);
    })
  }, function() {
        //iteration completed
  });

OR

 async.eachOfSeries(data, function(dataInstance, key, next) {
    functionCall(dataInstance, function(err , result){
        if(err)
          {
            console.log(err);
            next(err);
          }
          else
            next();
    });
  }, function() {
        //iteration completed
  });