Sunday 24 May 2020

Promise Resolution

This is related to this previous post, but it adds some value (for me at least), so I'll go ahead with this short post. Basically, in JavaScript a Promise will never resolve to another Promise, it will wait for the resolution of that second Promise and will resolve to its value. We come across this mainly when we have a Promise.then(handler) where that handler returns another Promise, e.g.:

let pr1 = new Promise(res => {
    setTimeout(() => {
        console.log(Date.now() + " resolving Promise");
        res("hello");
    }, 1000);
});

let pr2 = pr1.then(result => new Promise(res => {
    setTimeout(() => {
        console.log(Date.now() + " resolving Promise");
        res(result + " world");
    }, 3000);
}));

(async () => {
    let res = await pr2;
    //pr2 resolves when the promise returned by pr1.then handler resolves
    console.log(res);
})();

// 1590336489677 resolving Promise
// 1590336492702 resolving Promise
// hello world

The above is the behaviour explained in MDN:

the resolution/rejection of the promise returned by then will be subsequent to the resolution/rejection of the promise returned by the handler. Also, the resolved value of the promise returned by then will be the same as the resolved value of the promise returned by the handler.

But we have the same if we create a Promise with the Promise constructor and then the "action function" provided to the constructor returns also a Promise rather than returning a value:

let pr1 = new Promise(res => {
    console.log(Date.now() + " Promise 1 started");
    setTimeout(() => {
        let pr2 = new Promise(res2 => {
            console.log(Date.now() + " Promise 2 started");
            setTimeout(() => {
                console.log(Date.now() + " resolving Promise 2");
                res2("result");
            }, 3000);
        });
        console.log(Date.now() + " resolving Promise 1");
        res(pr2);
    }, 1000);
});

(async () => {
    let result = await pr1;
    console.log("result: " + result);
})();

// 1590337331838 Promise 1 started
// 1590337332874 Promise 2 started
// 1590337332875 resolving Promise 1
// 1590337335878 resolving Promise 2
// result: result

Additionally, while revisiting the MDN documentation for Promise.resolve() I've found 2 interesting points:

  • If the parameter that we pass to Promise.resolve is already a Promise, that promise is returned, rather than creating an second promise that will be resolved once the first one is resolved.
    let pr1 = Promise.resolve(5);
    let pr2 = Promise.resolve(pr1);
    pr1 === pr2;
    //true
    
  • The main use for Promise.resolve(value) is when we don't know if value is a normal value or a Promise:

    if (val instanceof Promise)
     val.then(result => console.log(result));
    else
     console.log(val);
     
    //rather than the above we can just do:
    Promise.resolve(val).then(result => console.log(result));
    
    

Notice than using await Promise.resolve() becomes unnecessary, as if we await for a non-promise the runtime will take care of wrapping the value in a Promise.

No comments:

Post a Comment