javascript - Node.js: Какие методы существуют для написания чистого, простого кода обратного вызова?




(4)

Известно, что код node.js превращается в спагетти обратного вызова.

Каковы наилучшие методы для преодоления этой проблемы и написания чистого, некомплексного, понятного кода обратного вызова в node.js?


Взгляните на обещания: http://promises-aplus.github.io/promises-spec/

Это открытый стандарт, предназначенный для решения этой проблемы.

Я использую модуль узла «q», который реализует этот стандарт: https://github.com/kriskowal/q

Простой вариант использования:

var Q = require('q');

Например, у нас есть метод вроде:

var foo = function(id) {
  var qdef = Q.defer();

  Model.find(id).success(function(result) {
    qdef.resolve(result);
  });

  return (qdef.promise);
}

Тогда мы можем связать обещания методом .then ():

foo(<any-id>)
.then(function(result) {
  // another promise
})
.then(function() {
  // so on
});

Также возможно создать обещание от таких значений, как:

Q([]).then(function(val) { val.push('foo') });

И многое другое, см. Документы.

Смотрите также:


Можно сделать несколько вещей, чтобы избежать «матриоски».

  • Вы можете хранить обратные вызовы для переменных:

    var on_read = function (foo, bar) {
          // some logic 
        },
    
        on_insert = function (err, data) {
          someAsyncRead(data, on_read);
        };
    
    someAsyncInsert('foo', on_insert);
    
  • Вы можете использовать некоторые modules которые помогают в этих сценариях.

    // Example using funk
    var funk = require('funk');
    for(var i = 0; i < 10; i++) {
      asyncFunction(i, funk.add(function (data) {
        this[i] = data;
      }));
    }
    
    funk.parallel(function () {
      console.log(this);
    });
    

Попробуйте узловую линию

https://github.com/kevin0571/node-line

Применение:

var line = require("line");
line(function(next) {
    obj.action1(param1, function(err, rs) {
        next({
            err: err,
            rs: rs
        });
    });
}, function(next, data) {
    if (data.err) {
        console.error(err);
        return;
    }
    obj.action2(param2, function(err, rs) {
        if (err) {
            console.error(err);
            return;
        }
        next(rs);
   });
}, function(rs) {
   obj.finish(rs);
});

Я бы предложил 1) использовать CoffeeScript и 2) использовать именованные обратные вызовы и передавать состояние между ними в хэше, а не вложенные обратные вызовы или разрешать списки аргументов очень долго. Поэтому вместо

var callback1 = function(foo) {
  var callback2 = function(bar) {
    var callback3 = function(baz) {
      doLastThing(foo, bar, baz);
    }
    doSomethingElse(bar, callback3);
  }
  doSomething(foo, callback2);
}
someAsync(callback1);

вы можете вместо этого просто написать

callback1 = (state) -> doSomething state.foo, callback2
callback2 = (state) -> doSomethingElse state.bar, callback3
callback3 = (state) -> doLastThing state
someAsync callback1

после вашего doSomething , doSomethingElse и doLastThing были переписаны для использования / расширения хэша. (Возможно, вам придется писать дополнительные обертки вокруг внешних функций.)

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







node.js