Search code examples
javascriptpromisebluebirdes6-promise

JavaScript Serial Promises with setTimeout


I am working on building Promise chain with setTimeouts in them. All of the Promises needs to be run in series not parallel. I am using Bluebird module to achieve serial flow of Promise execution.

Can someone please explain me why this code gives me output of 1,2,3,4 instead of 4,3,2,1?

var bluebirdPromise = require('bluebird');

function p1(value) {
    return new Promise(function(resolve, reject) {
       setTimeout(function(resolve) {
           console.log(value);
           resolve;
       }, value * 1000);
    });
}

var arr = [p1(4), p1(3), p1(2), p1(1)];

bluebirdPromise.reduce(arr,
    function(item, index, length) {

    }).then(function (result) {

    });


Solution

  • There are several issues:

    • The console.log you have is not made dependent on a previous resolved promise. There is just the time-out that determines when the output will happen. As you create all four promises at the "same" time, and thus all four setTimeout calls are invoked simultaneously, their callbacks will be called at the determined time-out. It does not matter how you chain promises afterwards... To solve this, you need to move the console.log in a then callback, because that callback will only be executed when the previous promise in the chain has been resolved.

    • The resolve function is not called in your code. You need to add parentheses.

    • The resolve parameter of the setTimeout callback hides the real function with the same name: you need to remove that parameter.

    Here is the suggested correction. For this snippet I have replaced the bluebird reduce with a standard Array#reduce, but it would work similarly with bluebird's reduce:

    function p1(value) {
        return new Promise(function(resolve, reject) {
           setTimeout(function() { // ***
               resolve(value); // ***
           }, value * 1000);
        });
    }
    
    var arr = [p1(4), p1(3), p1(2), p1(1)];
    
    arr.reduce(function(promise, next) {
        return promise.then(_ => next).then( value => {
            console.log(value); // ***
            return value;
        });
    }, Promise.resolve());