Search code examples
javascriptpromisees6-promise

JavaScript Promises: Chaining promise confusion


I've been playing with Promises and the chaining in the following example doesn't return the expected result. The getHeroChain() function works as expected, but the getHeroUnChain() function doesn't. In both cases, the execution order is as expected, but, in getHeroUnChain(), that last then function doesn't return the expected value (the HEROES array).

var HEROES = [{
    id: 11,
    name: 'Mr. Nice'
}, {
    id: 12,
    name: 'Narco'
}, ];

function getHeros() {
    return Promise.resolve(HEROES); // resolved promise
}

function getHerosSlowlyChained() {
    return new Promise(function(resolve, reject) {
        setTimeout(function() {
            console.log(" 1) inside setTimeout");
            resolve(2);
        }, 2000);

    }).then(function(value) {

        console.log(" 2) setTimeout resolved");
        console.log(" 2) inside 1st 'then' with value : " + value);
        return getHeros(); //return promise
    });
}

function getHerosSlowlyUnchained() { //not directly chained
    var mainPromise = new Promise(function(resolve, reject) {
        setTimeout(function() {
            console.log(" 1) inside setTimeout");
            resolve(2);
        }, 2000);
    });

    mainPromise.then(function(value) {

        console.log(" 2) setTimeout resolved");
        console.log(" 2) inside 1st 'then' with value : " + value);
        return getHeros(); //return promise

    });

    return mainPromise;
}

//Chained
function getHeroChain() {

    var heroPromise = getHerosSlowlyChained();

    heroPromise.then(function(heroes) {
        console.log(" 3) inside final 'then' with heroes :");
        console.log(heroes);
    });

}
//Un-Chained
function getHeroUnChain() {

    var heroPromise = getHerosSlowlyUnchained();

    heroPromise.then(function(heroes) {
        console.log(" 3) inside final 'then' with heroes :");
        console.log(heroes);
    });

}

//getHeroChain();
getHeroUnChain();

Output of getHeroChain():

1) inside setTimeout
2) setTimeout resolved
2) inside 1st 'then' with value : 2
3) inside final 'then' with heroes : [Object, Object]

Output of getHeroUnChain():

1) inside setTimeout
2) setTimeout resolved
2) inside 1st 'then' with value : 2
3) inside final 'then' with heroes : 2

JSBIN link : https://jsbin.com/pivoyuyawu/edit?js


Solution

  • This is because you return mainPromise in getHerosSlowlyUnchained. Every call to then or similar methods returns a new promise in the chain.

    In getHeroChain, your chain is: setTimeout -> setTimeout resolved-> final then.

    In getHeroUnChain your chain is: setTimeout -> [setTimeout resolved, final then].

    Note that in the second example, both setTimeout resolved and final then are after setTimeout. This means that both are given 2.

    To fix, either do

    return mainPromise.then(function(value) {
    
        console.log(" 2) setTimeout resolved");
        console.log(" 2) inside 1st 'then' with value : " + value);
        return getHeros(); //return promise
    
    });
    

    or

    mainPromise = mainPromise.then(function(value) {
    
        console.log(" 2) setTimeout resolved");
        console.log(" 2) inside 1st 'then' with value : " + value);
        return getHeros(); //return promise
    
    });
    return mainPromise;