Я пытаюсь избежать некоторого незначительного обратного вызова javascript Node.js с таким вкусом:

Я должен выполнить либо длинный асинхронный процесс A, либо B, а затем всегда выполнять C. В псевдокоде:

function example(flag, callback) {
    if (flag) {
        doLongProcessA(function(err, result) {
            if (err) return callback(err);
            doLongProcessC(result, function(err, finalResult) {
                if (err) return callback(err);
                return callback(null, finalResult);
            });
        });
    } else {
        doLongProcessB(function(err, result) {
            if (err) return callback(err);
            doLongProcessC(result, function(err, finalResult) {
                if (err) return callback(err);
                return callback(null, finalResult);
            });
        });
    }
}

Два вызова doLongProcessC не очень СУХИЕ. Я бы предпочел не разделять функцию на две части (одну с A или B и одну с C для их вызова). Кажется, что пакет Node async может решить эту проблему, но я не знаю, как это сделать. Может ли кто-нибудь дать пример решения? Спасибо!

0
Dan 22 Май 2014 в 03:06

2 ответа

Лучший ответ

Да, async - хороший выбор, чтобы избежать ада обратных вызовов в вашем коде.

Async.waterfall позволяет каждой функции в «конвейере» передавать свои результаты следующей функции.

В вашем примере и A, и B передают свои результаты следующей функции C.

Вы можете использовать асинхронный водопад следующим образом:

function example(flag, next) {

    async.waterfall(
        [
            function(callback) {
                if (flag) {
                    doLongProcessA(callback);
                } else {
                    doLongProcessB(callback);
                }
            },
            // If you want to differentiate the behavior of C in terms of flag, 
            // uncomment the flag param below
            function(/*flag,*/ result, callback) { 
                doLongProcessC(/*flag,*/ result, callback);
            }
        ],
        // if any function in the pipeline throws an err, 
        // it will immediately call this final function and return 
        function(err, result) {
            if (err!= null) {
                // put error handlers here
                return next(err);
            }
            // return the result
            return next(null, result);
        }
    };  
}

А doLongProcessA и doLongProcessB должны выглядеть так:

doLongProcessAorB(callback) 
{
    if (err) return callback(err, null)
    // do something here to fetch the result
    callback(null, /*flag, */ result);
}
1
BenMorel 1 Июл 2014 в 19:38

Я предпочитаю для этого обещания, если вы можете их использовать.

function example(flag, callback) {
  var longProcess = (flag) ? processa() : processb();
  longProcess
    .then(processc(callback))
    .fail(callback); // callback will be called with `err` argument
    // .done(doalways)) // if you need something like this
}

function processc(callback) {
  return function(results) {
    // do something with results
    callback(null, finalResults);
  }
}

Обновление . Больше обещаний, меньше агрегатора обратных вызовов.

function processa() {
  // do long process then `resolve(results)` when done or `reject(err)` on error
}

function processb() {
  // do long process then `resolve(results)` when done or `reject(err)` on error
}

function example(flag) {
  var longProcess = flag ? processa() : processb();
  return longProcess
    .then(function(results) {
      // process results
      return finalResults;
    });
}

var ex = example(flag)
  .then(function(finalResults) {
    // do something with final results
  })
  .fail(function(err) {
    // do something on fail
  });
-1
nowk 22 Май 2014 в 16:07