What is the best way to pass resolved promise valu

2019-01-30 15:57发布

问题:

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?

回答1:

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
});


回答2:

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.



回答3:

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 :)