javascript node.js 链接多个承诺(使用猫鼬)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/27937881/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
node.js chain multiple promises (with mongoose)
提问by Shih-Min Lee
The following is a typical promise function that I am dealing with.
以下是我正在处理的典型承诺函数。
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');
}
});
};
This looks ok until when I am dealing with more complicated update / creates the code will become really messy.
这看起来没问题,直到我处理更复杂的更新/创建代码会变得非常混乱。
Currently what I am doing with promise is that 1. I have a lot of useless return true statements and the only purpose is to go to next .then statement 2. promise are programmed in a nested style. also the input arguments are usually complicated and has more then 1 arguments so that I cannot do something like this
目前我对 promise 所做的是 1. 我有很多无用的 return true 语句,唯一的目的是转到下一个 .then 语句 2. promise 以嵌套样式编程。输入参数通常也很复杂,并且有超过 1 个参数,所以我不能做这样的事情
.then(fun1).then(fun2)
.then(fun1).then(fun2)
... etc
... 等等
which makes me unable to 'tap'
the .then
statement to enable/disable a functionality.
这使我无法'tap'
将.then
启用/禁用功能的语句。
So my questions is how do I do this correctly? Thanks..
所以我的问题是我该如何正确地做到这一点?谢谢..
the following is the really ugly things that I am talking about....
以下是我正在谈论的真正丑陋的事情......
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);
}
}
});
});
});
}
回答by Bergi
You can do two things:
你可以做两件事:
- Unnest
then
callbacks - Modularize. These "do product stuff" and "do inventory stuff" things might become their own functions (or even the same?).
- 取消嵌套
then
回调 - 模块化。这些“做产品的东西”和“做库存的东西”的东西可能会成为它们自己的功能(甚至相同?)。
In this case, unnesting could do the following (assuming you don't need closures in your commented sections):
在这种情况下,取消嵌套可以执行以下操作(假设您的评论部分不需要闭包):
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
});
}
回答by sbedulin
In my projects I use Async.js
在我的项目中我使用Async.js
I think you need to decompose your _process
method into small actions
我认为你需要将你的_process
方法分解成小动作
- Actions which depend on result from previous actions - async
waterfall
pattern might be used here - Actions which don't depend on the previous actions result, they may be executed in parallel
- Use some custom process
- 依赖于先前操作结果的操作 -
waterfall
此处可能使用异步模式 - 不依赖于先前动作结果的动作,它们可以并行执行
- 使用一些自定义流程
Here is an example from my app:
这是我的应用程序中的一个示例:
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(/* .... */);
});
Please refer to Async docs for a custom process, it really does contain a lot of common patterns, I also use this library in my client JavaScript.
请参阅 Async 文档以获取自定义流程,它确实包含很多常见模式,我也在我的客户端 JavaScript 中使用了这个库。