【问题标题】:How do you push function calls onto an array without calling them in Node JS for using Q?如何将函数调用推送到数组而不在 Node JS 中调用它们以使用 Q?
【发布时间】:2017-06-14 01:03:35
【问题描述】:

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

例如;

 //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
        });
    });
});

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

【问题讨论】:

  • 呃,Q.all 确实接受了一组承诺,而不是函数,所以你需要调用它们吗?
  • 基本上我希望能够创建一个函数数组以使用 Q.all([]) 调用,而无需在将它们添加到数组时调用它们。否则我会在添加它们时调用它们并在 Q.all([]) 中调用它们
  • 是的,您确实想立即给他们打电话。 Q.all 不会打电话给他们。我不明白为什么你的第一个 sn-p 不起作用。您的论点“我不想在 for 循环中调用它,因为它不会捕获任何错误并且我无法进一步处理响应。”有缺陷,您可以轻松捕获错误并处理结果通过链接then.
  • @aaaidan 我已经更新了我的答案,请检查

标签: arrays node.js dynamic promise q


【解决方案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
});

您可以使用 Q 所拥有的任何东西来代替 Promise.resolve(),作为创建已解决承诺的等价物

logToMongoFunction 将登录到 mongo 并需要返回一个承诺如果您需要等待它完成,然后再处理下一个数据项。如果您不需要等待 mongo 日志记录完成,则该函数无需返回承诺

【讨论】:

  • 如果functionCall得到一些数据库操作怎么办?例如,10000 长度的数组不会同时触发所有 10000 个请求吗?我认为应该有一个队列,应该控制这些循环
  • 如果没人发明裤子怎么办。我们都会穿裙子。
【解决方案2】:

我建议为此使用 Promise.mapSeries 或异步库,因为它很容易捕获错误。如果您在回调中有数据库调用,那么使用 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
  });

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

【讨论】:

  • 这里promise 和callbacks 混合在一起。使用其中任何一个都会更干净。
  • async + Promise 不能一起使用
  • @JaromandaX 为什么不呢?你能详细解释一下吗?因为我在异步中使用 Promise 没有任何问题。请详细解释或分享一些链接,以便我阅读
  • @JaromandaX 我用过它,从来没有遇到过问题。你能分享一些我可以阅读的链接吗?我只是想知道我是否做错了
  • 你做错的一件事是当一个函数抛出时,它会被再次调用(去试试看为什么)。将 Promise 与回调代码混合使用容易出错且不必要地复杂。它可以工作,但这不是一个好主意。
猜你喜欢
  • 2016-05-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-11
  • 2022-01-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多