0

Consider the following code which I took from https://stackoverflow.com/a/28250704/460084

function getExample() {
    var a = promiseA(…);
    var b = a.then(function(resultA) {
        // some processing
        return promiseB(…);
    });
    return Promise.all([a, b]).spread(function(resultA, resultB) {
        // more processing
        return // something using both resultA and resultB
    });
}

and a demo of the code I created https://jsfiddle.net/Lsobypup/

The idea is to run multiple promises and return some composite value based on their results.

What I don't understand is why in the code above promiseA runs only once ? it seems to me that with Promise.all([a, b]) it should run first when a is evaluated and then again when b is evaluated as it depends on a. But as the demo shows this does not happen.

Is there some magic in Promise.all to make this happen ? and what are the rules around this kind of behaviour ?

Community
  • 1
  • 1
kofifus
  • 17,260
  • 17
  • 99
  • 173
  • `it should run first when a is evaluated`: when do you think this happens? – Maria Ines Parnisari Jan 12 '16 at 12:05
  • is this an answer ? if I understood it I wouldn't ask – kofifus Jan 12 '16 at 12:07
  • No. It's a question. Do you think it happens in line `var a = promiseA()...`? – Maria Ines Parnisari Jan 12 '16 at 12:08
  • my question is not when it happens but why it doesn't happen twice. To answer your question - I don't know – kofifus Jan 12 '16 at 12:09
  • 1
    This is an interesting way to use promises, but basically when promiseA is created, it begins executing. b is another separate promise which begins executing when A ends successfully. Then, a third promise is created, which executes when both A and B have finished, and its parameters are the return values of each. It doesn't happen twice, because the Promise API is designed such that methods like .all and .then will have their callbacks execute immediately if the promise they are waiting for is already complete. – Rob Foley Jan 12 '16 at 12:28
  • 1
    You have to define carefully what you mean by "runs" and "evaluated". The `promiseA` function is called exactly once and therefore runs exactly once and returns a promise which is stored in `a`. When that promise is resolved, then the then callback is invoked which results in `promiseB` being invoked, the result of which is stored in `b`. Meanwhile, `Promise.all` sets up a condition of both promises fulfilling--it doesn't call anything, or execute anything, or run anything--it just waits for both promises to be fulfilled. –  Jan 12 '16 at 12:29
  • thank you Rob Foley and torazaburo ! would it be correct to think of a then onfullfil as an event that will run whenever the promise is fulfilled no matter when/where ? – kofifus Jan 12 '16 at 23:19

2 Answers2

1
var b = a.then(function(resultA) {
        // some processing
        return promiseB(…);
    });

This is chaining the result of a, which means if a is in a fulfilled state, the callback would immediately be invoked. Your resolution for promise a happens first as it's encountered first in the all() call. Once fulfilled, the final value sticks to the promise throughout.

As per this MDN reference:

Internally, a promise can be in one of three states:

  • Pending, when the final value is not available yet. This is the only state that may transition to one of the other two states.
  • Fulfilled, when and if the final value becomes available. A fulfillment value becomes permanently associated with the promise. This may be any value, including undefined.
  • Rejected, if an error prevented the final value from being determined. A rejection reason becomes permanently associated with the promise. This may be any value, including undefined, though it is generally an Error object, like in exception handling.
varevarao
  • 2,186
  • 13
  • 26
  • thanks ! you right 'the final value sticks to the promise throughout.' is that a featureofPromise.all() ? ... I am still confused, for example I changed the code to do Promise.all([a, a]) but promiseB onFulfilled is still called ! (see jsfiddle.net/Lsobypup/2) why ? – kofifus Jan 12 '16 at 20:44
  • That's a property of Promises in general. To answer your follow-up, if you refer the ref I've linked above, you'll see the line: **"Once you have a reference to a promise, you can call its then() method to execute an action when the value becomes available, or when an error occurs."** Which means the `then()` you called on the reference to `var a` will be executed as soon as promiseA is resolved, whether or not `var b` was invoked. If you see the final alert box in your fiddle though, because you changed the params to `[a, a]`, you'll see the results are only for promiseA. – varevarao Jan 13 '16 at 06:58
0

It will be great for use bluebird module http://bluebirdjs.com/docs/api/promise.props.html

const Promise = require("bluebird");
Promise.props({
    pictures: getPictures(),
    comments: getComments(),
    tweets: getTweets()
})
.then(function(result) {
    console.log(result.tweets, result.pictures, result.comments);
});
аlex
  • 5,426
  • 1
  • 29
  • 38