Параллельный асинхронный вызов Nodejs, но с приоритетом

Предположим, я использую Node.js, чтобы попытаться выполнить два асинхронных вызова, чтобы получить ответы. Я знаю, что есть асинхронный пакет, в котором вы можете просто передать две функции и необязательный обратный вызов.

async.parallel([fun1(){callback(null,1);},
fun2(){callback(null,2);}],
function(err, results) {  
});

Но предположим, что сейчас у меня есть приоритет, если fun1 возвращает значение, то мне не нужен ответ fun2, только если fun1 возвращает null, то я жду fun2. Поэтому я не хочу использовать функцию обратного вызова, потому что обратный вызов ожидает завершения обеих функций, а fun2 может занять очень много времени.

Прямо сейчас я просто использую очень исчерпывающий способ, создавая функцию обратного вызова для обоих асинхронных вызовов.

function(){
    var theAnswer,FromFun1,FromFun2;
    var reply1,reply2;
    fun1(reply1="answered";FromFun1=1;complete());
    fun2(reply2="answered";FromFun2=2;complete());
   function complete(answer){
      if(reply1=="answered"){
           theAnswer=FromFun1;
      }else if(reply1==null){
           // Don't do anything because fun1 is not finished running. 
       }else if(reply2=="answered"){
           theAnswer=FromFun2;
       }else{
           // Both have no answer, err.
       }
   }
}

Есть лучший способ это сделать?


person Evilsanta    schedule 21.07.2014    source источник
comment
Вместо этого вы должны попробовать обещания. Это было бы так же просто, как var second = fun2(); return fun1().then(function(r) { return r || second; })   -  person Bergi    schedule 22.07.2014
comment
Спасибо Берги, это было полезно. Я бы проголосовал за тебя :)   -  person Evilsanta    schedule 22.07.2014
comment
Спасибо @Bergi, это было полезно. Я бы проголосовал за вас :). У меня есть еще один вопрос. В then() он либо возвращает r, что является ответом, либо 'second', что является обещанием. Как мне справиться с этим дальше?   -  person Evilsanta    schedule 22.07.2014
comment
Если вы вернете ответ, он будет использовать его, если вы вернете обещание от then, он будет ждать этого. В этом и смысл then :-)   -  person Bergi    schedule 22.07.2014


Ответы (2)


Трюк, который я использовал для этого сценария, заключается в том, чтобы вернуть «выполнено» в первом аргументе обратного вызова:

async.parallel([
  function(callback){
    callback("done",1);
  },
  function(callback){
    callback(null,2);
  }
], function(err, results) { 
  console.log(err, results);   // done [ 1 ] or done [ 1 , 2 ] 
});

Звучит как хак, и я обычно этого не делаю, но в некоторых редких случаях, таких как этот, это на самом деле сохраняет код в чистоте... просто задокументируйте это, чтобы другие знали, каково ваше намерение.

person Ben    schedule 21.07.2014
comment
Использование исключений для потока управления, особенно для коротких асинхронных функций, — умный хак :-) - person Bergi; 22.07.2014

Лучше использовать водопад вместо параллельного выполнения, потому что вы можете передать результат своей предыдущей функции следующей в качестве аргумента.

async.waterfall([
function(callback){
    callback(null, 'one');
},
function(arg1, callback){

    // arg1 now equals 'one'
   if(arg1==null){
   // it will not take time it returns immediately 
    callback(null, 'done');

    }else{
    // do your another stuff here fun2 logic here 
    // it will not be executed and so it dont take time 
      }
  }
  ], function (err, result) {
  // result now equals 'done'    
}); 
person Vivek Bajpai    schedule 21.07.2014
comment
Означает ли это, что функции в водопаде являются последовательными? - person Evilsanta; 21.07.2014
comment
да, они последовательные, но они не заняли много времени - person Vivek Bajpai; 21.07.2014
comment
Преимущество OP в том, что обе функции выполняются параллельно; это должно принести пользу, следует использовать. Водопад происходит последовательно, поэтому, хотя это элегантное решение, оно не является полностью оптимальным. - person zamnuts; 21.07.2014
comment
@zamnuts я знаю, что это не оптимальное решение, но, как утверждает OP, выполнение второй функции зависит от вывода первой, поэтому я не думаю, что это можно сделать параллельно. - person Vivek Bajpai; 21.07.2014
comment
@VivekBajpai возможно, если после того, как какая-либо из функций вернет действительный результат, она может отменить / прервать оставшуюся ожидающую функцию, но это зависит от того, что происходит внутри (например, что-то с сокетом). - person zamnuts; 21.07.2014
comment
Я думаю, что OP нужно сначала проверить вывод func1, а затем перейти ко второму, поэтому, когда он вызывает вторую функцию с нулевым аргументом, она возвращает прямо - person Vivek Bajpai; 21.07.2014