任何build立方便的callback写作风格的JavaScript?

callback在编码中越来越需要,特别是当你考虑Node.JS的非阻塞工作风格的时候。 但是很快写很多协程callback变得难以回读。

例如,想像这样的东西金字塔 :

 // This asynchronous coding style is really annoying. Anyone invented a better way yet? // Count, remove, re-count (verify) and log. col.count(quertFilter, function(err, countFiltered) { col.count(queryCached, function(err, countCached) { col.remove(query, function(err) { col.count(queryAll, function(err, countTotal) { util.log(util.format('MongoDB cleanup: %d filtered and %d cached records removed. %d last-minute records left.', countFiltered, countCached, countTotal)); }); }); }); }); 

是我们经常看到的东西,而且很容易变得更加复杂。

当每个函数的长度至less为几行时,分离函数开始变得可行:

 // Imagine something more complex function mary(data, pictures) { // Do something drastic } // I want to do mary(), but I need to write how before actually starting. function nana(callback, cbFinal) { // Get stuff from database or something callback(nene, cbFinal, data); } function nene(callback, cbFinal, data) { // Do stuff with data callback(nini, cbFinal, data); } function nini(callback, data) { // Look up pictures of Jeff Atwood callback(data, pictures); } // I start here, so this story doesn't read like a book even if it's quite straightforward. nana(nene, mary); 

但是一直都有很多传言。 随着其他function写在这之间,这变得难以阅读。 这些function本身可能太小而不足以certificate给他们自己的文件。

一个不同的callback方法是承诺。

例如:jQuery Ajax。 这个可能看起来很熟悉。

 $.ajax({ url: '/foo', success: function() { alert('bar'); } }); 

但$ .ajax也返回一个承诺。

 var request = $.ajax({ url: '/foo' }); request.done(function() { alert('bar'); }); 

一个好处是,你模拟同步行为,因为你可以使用返回的诺言,而不是提供一个callback到$ .ajax.success和一个callbackcallback和callback….另一个优点是,你可以链/聚合承诺,并且如果你愿意的话,有一个promise-aggregate的error handling器。

我发现这篇文章是非常有用的。 它描述了callback,承诺和其他技术的利弊。

一个stream行的实现(例如AngularJS iirc使用)是Q.

使用async等asynchronousstream程控制库。 它提供了一个干净的方法来构造需要多个asynchronous调用的代码,同时保持它们之间存在的依赖关系(如果有的话)。

在你的例子中,你会做这样的事情:

 async.series([ function(callback) { col.count(queryFilter, callback); }, function(callback) { col.count(queryCached, callback); }, function(callback) { col.remove(query, callback); }, function(callback) { col.count(queryAll, callback); } ], function (err, results) { if (!err) { util.log(util.format('MongoDB cleanup: %d filtered and %d cached records removed. %d last-minute records left.', results[0], results[1], results[3])); } }); 

这将执行每个function串联; 一旦第一个调用它的callback,第二个调用,依此类推。 但是您也可以使用parallelwaterfall或任何与您正在查找的stream程匹配的stream程。 我发现它比使用承诺更清洁。

综合答案和文章。 请编辑这个答案,并添加图书馆/例子/ doc-urls在一个简单的方法为每个人的利益。

承诺文件

  • 具有承诺的asynchronous控制stream程
  • jQuery延期

asynchronous库

  • async.js

     async.waterfall([ function(){ // ... }, function(){ // ... } ], callback); 
  • 节点光纤

  •  Step( function func1() { // ... return value }, function func2(err, value) { // ... return value }, function funcFinal(err, value) { if (err) throw err; // ... } ); 
  • Q

     Q.fcall(func1) .then(func2) .then(func3) .then(funcSucces, funcError) 
    • API参考
    • 模式的例子
    • 更多文档