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
.then(fun1).then(fun2)
... etc
which makes me unable to 'tap'
the .then
statement to enable/disable a functionality.
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);
}
}
});
});
});
}
In this approach, we will use Promise. all() method which takes all promises in a single array as its input. As a result, this method executes all the promises in itself and returns a new single promise in which the values of all the other promises are combined together.
The Mongoose Query class provides a chaining interface for finding, updating, and deleting documents.
Assuming we have the processing power and that our promises can run in parallel, there is a hard limit of just over 2 million promises.
Example 2: Chaining the Promise with then() Promise resolved You can call multiple functions this way. In the above program, the then() method is used to chain the functions to the promise. The then() method is called when the promise is resolved successfully. You can chain multiple then() methods with the promise.
You can do two things:
then
callbacksIn 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
});
}
In my projects I use Async.js
I think you need to decompose your _process
method into small actions
waterfall
pattern might be used hereHere 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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With