Node.js:编写干净简单的回调代码有哪些技巧?

时间:2011-03-10 20:49:07

标签: javascript node.js

node.js代码已知会变成回调意大利面。

在node.js中克服此问题并编写干净,不复杂,易于理解的回调代码的最佳技巧是什么?

5 个答案:

答案 0 :(得分:8)

看看Promises: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') });

还有更多,请参阅文档。

另见:

答案 1 :(得分:4)

可以采取一些措施来避免'matrioska风格'。

  • 您可以将回调存储到变量中:

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

答案 2 :(得分:2)

我建议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

您的doSomethingdoSomethingElsedoLastThing被重写后,使用/扩展哈希值。 (您可能需要围绕外部函数编写额外的包装器。)

正如您所看到的,此方法中的代码读取整齐且线性。并且因为所有回调都暴露出来,单元测试变得更加容易。

答案 3 :(得分:0)

尝试节点行

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

答案 4 :(得分:0)

在大多数情况下,使用Twitter的OAuth2应用程序示例,使用Kris的Q promise库和RegisterFormset = modelformset_factory(Register, form=ModbusRegistersForm) register_forms = RegisterFormset() ,Nodejs Express api route。首次尝试用户时间线GET。如果401响应,则刷新bearer-token然后重试用户时间线。我不得不使用https.request来处理一个返回另一个promise(链接)或值的promise。

Q.when