Marko Marko - 1 month ago 12
Javascript Question

Javascript chained promises

I have 3 ajax calls that I simulate in the demo code with setTimeout functions. I'll start with a piece of code that works fine: all the calls are made in parallel and I'm expecting all to succees, otherwise there's an error.

var p1 = function () {
return new Promise(function (resolve, reject) {
setTimeout(function () {
console.log('p1');
resolve(1);
//reject(1);
}, 2000);
});
};

var p2 = function () {
return new Promise(function (resolve, reject) {
setTimeout(function () {
console.log('p2');
resolve(2);
//reject(2);
}, 1000);
});
};

var p3 = function () {
return new Promise(function (resolve, reject) {
setTimeout(function () {
console.log('p3');
resolve(3);
//reject(3);
}, 5000);
});
};

Promise.all([p1(), p2(), p3()])
.then(values => {
console.log(values);
}).catch(values => {
console.log("error: " + values);
});


Now, the important change to make is that p2 has to execute only after p1 ended with success and in no other case. Here's the new code, but this one doesn't wok att all:

var p1 = function () {
return new Promise(function (resolve, reject) {
setTimeout(function () {
console.log('p1');
resolve(1);
//reject(1);
}, 2000);
});
};

var p2 = function () {
return new Promise(function (resolve, reject) {
setTimeout(function () {
console.log('p2');
resolve(2);
//reject(2);
}, 1000);
});
};

var p21 = function() {
return new Promise(function (resolve, reject) {
p1().then(function (data) { p2(); })
});
};

var p3 = function () {
return new Promise(function (resolve, reject) {
setTimeout(function () {
console.log('p3');
resolve(3);
//reject(3);
}, 5000);
});
};

Promise.all([p21(), p3()])
.then(values => {
console.log(values);
}).catch(values => {
console.log("error: " + values);
});


I have read various tutorials on how to deal with JS promises, bit I'm still unable to correct my problem.

Note that time delays used in test functions are just an example, the code is supposed to work regardlessly of the relative duration of the functions (ie. weather each one is slower or faster).

Answer

You can make promises synchronous by returning next promise call in previous promise's next() function. It sounds complicated but it's quite simple:

/*
* Remains the very same
*/

var p1 = function () {
    return new Promise(function (resolve, reject) {
        setTimeout(function () {
            console.log('p1');
            resolve(1);
            //reject(1);
        }, 2000);
    });
};

var p2 = function () {
    return new Promise(function (resolve, reject) {
        setTimeout(function () {
            console.log('p2');
            resolve(2);
            //reject(2);
        }, 1000);
    });
};

var p3 = function () {
    return new Promise(function (resolve, reject) {
        setTimeout(function () {
            console.log('p3');
            resolve(3);
            //reject(3);
        }, 5000);
    });
};

// If you want to run p1 and p3 in "parallel" + after p1 is finished run p2
Promise.all([p1().then(valuesFromP1 => {
    return p2();
}), p3()]).then(values => {
    // all 3 finished
})


// Or alternatively something similar but slightly different - see the comments
Promise.all([p1().then(valuesFromP1 => {
         // handle p1 is done
         p2().then(valuesFromP2 => {
            // handle p2 is done
         });
     }), p3()])
     .then(values => {
         // handle p1 and p3 are done but you don't care about p2
     });


// Or if you don't care about common finish of p1 and p2 you can simply do this
p1().then(valuesFromP1 => {
     // handle p1 is done
     p2().then(valuesFromP2 => {
        // handle p2 is done
     });
});
p3().then(valuesFromP3 => {
     // handle p3 is done
});

Frank