找回内部callback的另一个发现(…),如何逃离callback地狱?

(第一:对不起,我不太会说英文!)

我想在一个数组中返回3个发现的结果。 我的代码(下)运行良好,但我在callback地狱!

_Schema .static('retrieveAll', function(cb) { query = {}; this.find(query, function(err, data) { if(err) { cb(err, null); return; } if(data) all = data; else all = []; _StoresModel.find(query).select('contact address').exec(function(err, data) { if(err) { cb(err, null); return; } if(data) { all = data.reduce(function(coll, item) { coll.push(item); return coll; }, all); } _CustomersModel.find(query).select('contact address').exec(function(err, data) { if(err) { cb(err, null); return; } if(data) { all = data.reduce(function(coll, item) { coll.push(item); return coll; }, all); } cb(null, all); }); }); }); }); 

我find了FIND里面的FIND。 有没有改进这个?

解:

_Schema .static('retrieveAll',function(cb){var model = this;

 _async.parallel( { contacts: function(cb) { model.find({}).exec(cb); } , stores: function(cb) { _StoresModel.find({}).select('contact address').exec(cb); } , costumers: function(cb) { _CostumersModel.find({}).select('contact address').exec(cb); } } , function(err, data) { if(err) { cb(err, null); return } var ret = []; if(data.contacts.length > 0) { ret = ret.concat(data.contacts); } if(data.stores.length > 0) { ret = ret.concat(data.stores); } if(data.costumers.length > 0) { ret = ret.concat(data.costumers); } cb(null, ret); }); 

看看npm Async 。 它是node.js上可以使用的不同模式的一个很好的库。

如果按时间顺序优先或并行模式(如果它们都可以并行执行),则可能需要使用瀑布 。

你可以尝试使用Promise 。

(未经testing)例如:

 var RSVP = require('rsvp'); var all = []; _Schema.static('retrieveAll', function(cb) { query = {}; findPromise(this, query) .then(function (data) { all = data; return findPromise(_StoresModel, query, 'contact address'); }) .then(function (stores) { all = all.concat(stores); return findPromise(_CustomersModel, query, 'contact address'); }) .then(function (customers) { all = all.concat(customers); cb(null, all); }) .catch(function (err) { cb(err, null); }); }); function findPromise(Model, query, select) { return new RSVP.Promise(function (resolve, reject) { Model.find(query).select(select || '*').exec(function (err, data) { return err ? reject(err) : resolve(data); }); }); } 

这个例子是使用RSVP ,但也有其他承诺的实现,如Q和蓝鸟 。

另外,还可以使用concat来连接数组,而不是使用reduce

一些像q和bluebird这样的服务器端的承诺库会大大地清理你的代码,并消除callback地狱的混乱。