node.js链多重承诺(mongoose)

以下是我正在处理的典型承诺函数。

var _delete = function(t, id) { return Promise.cast(Event.find({where: {id: id}}, {transaction: t})) .then(function(d){ if (d) { // ------- (*) return Promise.cast(d.updateAttributes({status: -1}, {transaction: t})) .then(function(){ // do inventory stuff return Promise.cast(Inventory.update({}).exec()) .then(function(d){ // do something }) }).then(function(){ // do product stuff return Promise.cast(Product.update({}).exec()) .then(function(d){ // do something }) }) } else { return Promise.reject('this transaction list does not exist'); } }); }; 

这看起来不错,直到当我正在处理更复杂的更新/创build代码将变得非常混乱。

目前我正在做的与承诺是,我有很多无用的返回真正的声明,唯一的目的是去接下来的声明2.承诺编程嵌套风格。 input参数通常也很复杂,而且有更多的参数,所以我不能这样做

.then(fun1).then(fun2)

…等

这使我无法'tap' .then语句来启用/禁用某个function。

所以我的问题是如何正确地做到这一点? 谢谢..


以下是我谈论的真正丑陋的东西….

 var _process = function(t, tid) { var that = this; return Promise.cast(Usermain.find({where: {transaction_id: tid}})) .bind({}) // --- (*) .then(function(d){ this.tmain = d; return true; // ---- do nothing, just go to next thennable (is this correct) }).then(function(){ return Promise.cast(Userlist.findAndCountAll({where: {transaction_id: tid}})) }).then(function(d){ this.tlist = d; return true; // ---- do nothing, just go to next thennable (is this correct) }).then(function(){ if (this.tmain.is_processed) { return Promise.reject('something is wrong'); } if (this.tlist.count !== this.tmain.num_of_tran) { return Promise.reject('wrong'); } return Promise.resolve(JSON.parse(JSON.stringify(this.tlist.rows))) .map(function(d){ if (d.is_processed) return Promise.reject('something is wrong with tran list'); return true; // goto next then }); }).then(function(){ return Promise.cast(this.tmain.updateAttributes({is_processed: 1}, {transaction: t})); }).then(function(){ return Promise.resolve(this.tlist.rows) .map(function(d){ var tranlist = JSON.parse(JSON.stringify(d)); return Promise.cast(d.updateAttributes({is_processed: 1, date_processed: Date.now()}, {transaction: t})) .then(function(d){ if (!d) { return Promise.reject('cannot update tran main somehow'); } else { if (tranlist.amount < 0) { return Usermoney._payBalance(t, tranlist.user_id, -tranlist.amount); } else { return Usermoney._receiveBalance(t, tranlist.user_id, tranlist.amount); } } }); }); }); } 

你可以做两件事情:

  • Unnest thencallback
  • 模块化。 这些“做产品的东西”和“做库存的东西”的东西可能成为自己的function(甚至是相同的?)。

在这种情况下,unnesting可以做到以下几点(假设你不需要在注释部分closures):

 function _delete(t, id) { return Promise.cast(Event.find({where: {id: id}}, {transaction: t})) .then(function(d){ if (d) { return Promise.cast(d.updateAttributes({status: -1}, {transaction: t})); else throw new Error('this transaction list does not exist'); }) .then(function(){ // do inventory stuff return Promise.cast(Inventory.update({}).exec()) }) .then(function(d){ // do something }) .then(function(){ // do product stuff return Promise.cast(Product.update({}).exec()) }) .then(function(d){ // do something }); } 

在我的项目中,我使用Async.js

我认为你需要将你的_process方法分解成_process

  1. 依赖于以前的操作结果的操作 – asynchronouswaterfall模式可能在这里使用
  2. 不依赖于前面的动作的动作可以并行执行
  3. 使用一些自定义过程

这里是我的应用程序的一个例子:

 async.waterfall([ function findUser(next) { Users.findById(userId, function (err, user){ if(err) { next(new Error(util.format('User [%s] was not found.', userId))); return; } next(null, user); }); }, function findUserStoriesAndSurveys(user, next) { async.parallel([ function findStories(callback) { // find all user stories Stories.find({ UserGroups: { $in : user.Groups } }) .populate('Topic') .populate('Episodes') .exec(function(err, stories) { if(err) { callback(err); return; } callback(null, stories); }); }, function findSurveys(callback) { // find all completed surveys Surveys.find({ User: user }).exec(function(err, surveys) { if(err) { callback(err); return; } callback(null, surveys); }); } ], function(err, results) { if(err) { next(err); return; } next(null, results[0], results[1]); }); }, function calculateResult(stories, surveys, next) { // do sth with stories and surveys next(null, { /* result object */ }); } ], function (err, resultObject) { if (err) { res.render('error_template', { status: 500, message: 'Oops! Server error! Please reload the page.' }); } res.send(/* .... */); }); 

请参考Async文档中的一个自定义过程,它确实包含了很多常见模式,我也在我的客户端JavaScript中使用这个库。