Node.js异步,但只处理第一个正/定义结果

时间:2015-09-01 04:35:15

标签: javascript node.js asynchronous

创建并行异步HTTP请求的最佳方法是什么,并将第一个结果带回正面?我熟悉JavaScript的异步库,很乐意使用它,但不确定它是否完全符合我的要求。

背景 - 我有一个Redis商店,作为服务器的状态。我们可以调用一个API来获取一些数据,这些数据比到达Redis商店需要更长的时间。

在大多数情况下,数据已经存在于Redis商店中,但在某些情况下它还不存在,我们需要从API中检索它。

简单的做法是查询Redis,如果该值不在Redis中,则转到API。但是,如果数据尚未存在于我们的Redis缓存中,我们将不必要地丢失20-50毫秒,并且在无法使用Redis查找数据后我们必须转到API。由于这个特定的API服务器负载不是很大,因此即使我们不是绝对需要返回的值,也不会同时/并行地访问API。

//下面的伪代码

async.minimum([

function apiRequest(cb){
   request(opts,function(err,response,body){
         cb(err,body.result.hit);
    }
},
function redisRequest(cb){
   client.get("some_key", function(err, reply) {
          cb(err,reply.result.hit);
     });
}], 

  function minimumCompleted(err,result){

   // this mimimumCompleted final callback function will be only fired once, 
   // and would be fired by one of the above functions - 
   // whichever one *first* returned a defined value for result.hit


 });

有没有办法通过异步库或者承诺获得我想要的东西,或者我应该自己实现一些东西?

3 个答案:

答案 0 :(得分:1)

使用Promise.any([ap, bp])

以下是没有承诺的可行方法。它未经测试但应符合要求。

为了满足返回第一次成功而不仅仅是第一次完成的要求,我保留了预期完成次数的计数,这样如果发生错误,除非是最后一次错误,否则可以忽略它。

function asyncMinimum(a, cb) {
    var triggered = false;
    var completions = a.length;
    function callback(err, data) {
      completions--;
      if (err && completions !== 0) return;
      if (triggered) return;
      triggered = true;
      return cb(err, data);
    }
    a.map(function (f) { return f(callback); });
}


asyncMinimum([

function apiRequest(cb){
   request(opts,function(err,response,body){
         cb(err,body.result.hit);
    }
},
function redisRequest(cb){
   client.get("some_key", function(err, reply) {
          cb(err,reply.result.hit);
     });
}], 

  function minimumCompleted(err,result){

   // this mimimumCompleted final callback function will be only fired once, 
   // and would be fired by one of the above functions - 
   // whichever one had a value for body.result.hit that was defined

 });

答案 1 :(得分:1)

async.js库(甚至是promises)通过使用计数器跟踪待处理的异步操作的数量。您可以在回答此相关问题时看到该想法的简单实现:http://www.example.com?Ana

我们可以使用相同的概念来实现您想要的minimum函数。只是,在触发最终回调之前,我们不是等待计数器计算所有响应,而是故意触发第一个响应的最终回调并忽略所有其他响应:

// IMHO, "first" is a better name than "minimum":

function first (async_functions, callback) {
    var called_back = false;

    var cb = function () {
        if (!called_back) {
            called_back = true; // block all other responses

            callback.apply(null,arguments)
        }
    }

    for (var i=0;i<async_functions.length;i++) {
        async_functions[i](cb);
    }
}

使用它就像下面这样简单:

first([apiRequest,redisRequest],function(err,result){
    // ...
});

答案 2 :(得分:1)

这是一种使用promises的方法。由于您正在寻找的非标准结果,它需要一些额外的自定义代码。您不只是在寻找第一个不返回错误,但您正在寻找具有特定类型结果的第一个,以便采用自定义结果检查器功能。并且,如果没有得到结果,那么我们也需要通过拒绝承诺将其传达给调用者。这是代码:

resolve()

调用.then()的第一个承诺将触发{{1}}处理程序。如果两者都未能获得命中,那么它将拒绝承诺。