This question already has an answer here:
-
How do I access previous promise results in a .then() chain?
15 answers
I'm trying to get my head around promises, using the Q module in node.js, however I have a small issue.
In this example:
ModelA.create(/* params */)
.then(function(modelA){
return ModelB.create(/* params */);
})
.then(function(modelB){
return ModelC.create(/* params */);
})
.then(function(modelC){
// need to do stuff with modelA, modelB and modelC
})
.fail(/*do failure stuff*/);
The .create method returns a promise then in each .then(), as expected one gets the resolved value of the promise.
However in the final .then() I need to have all 3 previously resolved promise values.
What would be the best way to do this?
These are some of your many options:
Behind door 1, use reduce to accumulate the results in series.
var models = [];
[
function () {
return ModelA.create(/*...*/);
},
function () {
return ModelB.create(/*...*/);
},
function () {
return ModelC.create(/*...*/);
}
].reduce(function (ready, makeModel) {
return ready.then(function () {
return makeModel().then(function (model) {
models.push(model);
});
});
}, Q())
.catch(function (error) {
// handle errors
});
Behind door 2, pack the accumulated models into an array, and unpack with spread.
Q.try(function () {
return ModelA.create(/* params */)
})
.then(function(modelA){
return [modelA, ModelB.create(/* params */)];
})
.spread(function(modelA, modelB){
return [modelA, modelB, ModelC.create(/* params */)];
})
.spread(function(modelA, modelB, modelC){
// need to do stuff with modelA, modelB and modelC
})
.catch(/*do failure stuff*/);
Behind door 3, capture the results in the parent scope:
var models [];
ModelA.create(/* params */)
.then(function(modelA){
models.push(modelA);
return ModelB.create(/* params */);
})
.then(function(modelB){
models.push(modelB);
return ModelC.create(/* params */);
})
.then(function(modelC){
models.push(modelC);
// need to do stuff with models
})
.catch(function (error) {
// handle error
});
The Bluebird promises library provides another solution for this via .bind()
.
It looks like this:
ModelA.create(/* params */).bind({})
.then(function (modelA) {
this.modelA = modelA;
return ModelB.create(/* params */);
})
.then(function (modelB) {
this.modelB = modelB;
return ModelC.create(/* params */);
})
.then(function (modelC) {
// you have access to this.modelA, this.modelB and modelC;
});
There is a lot of interesting information about this method in the documentation.
You probably doesn't need to wait until modelA is created to create modelB and so on.
If this is true, then you can do the following:
var promises = [
ModelA.create(...),
ModelB.create(...),
ModelC.create(...)
);
Q.all( promises ).spread(function( modelA, modelB, modelC ) {
// Do things with them!
}).fail(function() {
// Oh noes :(
});
What this does is:
- Create an array of promises, with one promise for each model you need;
- Execute all 3 promises in parallel;
- Execute a function passed in
spread()
when all 3 promises are done. The arguments are the resolved values for each promise, in the declaration order.
I hope it helps you :)