Search code examples
javascriptnode.jsecmascript-6es6-promise

javascript ES6 dynamically chaining promises


I'm trying to chain promises dynamically in order to deal with an unknown amount of asynchronous calls that need to happen in order. I'm using IO.JS/chrome which supports Promise's natively.

The creation of the promise fires immediately (at least relatively to console output). I was expecting to be able to collect promises then pass to Promise.all, but by that time they've already fired for reasons I don't understand.

Here's one method of chaining then, suggested by a comment on Dynamic Chaining in Javascript Promises

            var lastPr = null;
            console.log(" exit setup......................");
            while(this.statesToExit.length > 0) {


                var v = this.statesToExit.shift();
                console.log("new Promise...");
                var pr = new Promise(function (resolve, reject) {

                    console.log("doing Exit stuff at time " +curTime); 
                    resolve();  //SOMETHING MORE SUBSTANTIAL GOES HERE

                });

                console.log("lastPr.then.");
               if (lastPr != null) {
                    lastPr.then(pr);
                }
                lastPr = pr;
              //  console.log("adding pr to worklist");
               // promiseList.push(pr);
                // });
            }

The other approach is

            var promiseList= [];
            console.log(" exit setup......................");
            while(this.statesToExit.length > 0) {


                var v = this.statesToExit.shift();
                console.log("new Promise...");
                var pr = new Promise(function (resolve, reject) {

                    console.log("doing Exit stuff at time " +curTime); 
                    resolve();  //SOMETHING MORE SUBSTANTIAL GOES HERE

                });

                console.log("adding pr to worklist");
                promiseList.push(pr);
                 });
            }
 console.log("Transition *START*-" +promiseList.length +" ");
       Promise.all(promiseList).catch(function(error) {
            console.log("Part of TransitionCursor Failed!", error);
        }).then(this.summarizeWorkDone());

In both cases the output is like

new Promise...
doing Exit stuff at time 0
new Promise...
doing Exit stuff at time 0
    "Transition *START*-"

vs the expected

new Promise...
new Promise...
    "Transition *START*-"
doing Exit stuff at time 0
doing Exit stuff at time 0

How do I dynamically create a list of promises to later execute?


Solution

  • Ok,

    So people are voting down my answer because I provided the external link, which in fact was written by me. So sad! So modifying the answer and the previous answer goes at the bottom of this answer.

    Here, I shall focus some light on the problems on the first example because that's what I have explained in the link at the bottom of this post.

    First of all: you are not chaining promises but creating multiple promises. When you create a promise, the function that you pass to the constructor gets called immediately. Check section 1 of the tutorial in the link below for details. That's why you get the output line 'doing Exit stuff at time ...' after 'new promise' line. You did not say anything about curTime but it seems that the values are not right although that's not the focus of this post.

    Secondly, you should assign lastPr.then() to lastPr() but you are assigning the newly created pr to lastPr. This was explained in section 2 of the link below.

    Thirdly, I would say that your expected output says that I should remind you that the function passed to promise constructor starts immediately. So you should not print anything during the promise creation and rather push them down in then() methods. However, I am not doing this here and so you will see that the first 'doing Exit stuff at time 0' line appears just after the first 'new Promise...' line.

    Fourthly, you did not show 'lastPr.then.' in expected output

    Note: I changed your code's curTime and statesToExit (removed 'this' reference and assigned test array)

    I would suggest something like this:

    var curTime = 0;
    var lastPr = null;
    console.log(" exit setup......................");
    var statesToExit = [1, 2, 3]; // NOTE: the change to make this code runnable.
    while (statesToExit.length > 0) {
        var v = statesToExit.shift();
        console.log("new Promise...");
    
        if (lastPr == null) {
            lastPr = new Promise(function (resolve, reject) {
                console.log("doing Exit stuff at time " + curTime);
                resolve();  //SOMETHING MORE SUBSTANTIAL GOES HERE
            });
        }
        else {
    
            console.log("lastPr.then."); // NOTE: This does not appear in your expected output
            lastPr = lastPr.then(result => {
                console.log("doing Exit stuff at time " + curTime);
                return Promise.resolve();  //SOMETHING MORE SUBSTANTIAL GOES HERE
            });
        }
        //  console.log("adding pr to worklist");
        // promiseList.push(pr);
        // });
    }
    
    // NOTE: now you need to esecute the chain:
    // you should handle promise rejection:
    // check the tutorial link:
    // https://github.com/tuhinpaul/syp-model/wiki/Programmatic-Chaining-and-Recursive-Functions-with-JavaScript-Promise
    lastPr.catch(err => { console.log(err); });
    

    The output of the above code:

     exit setup......................
    new Promise...
    doing Exit stuff at time 0
    new Promise...
    lastPr.then.
    new Promise...
    lastPr.then.
    doing Exit stuff at time 0
    doing Exit stuff at time 0
    

    I described dynamic promise chaining in the following tutorial: check the following tutorial for

    1. programmatic (dynamic) chaining of javascript/node.js promises and
    2. Promise chaining using recursive functions

    Programmatic-Chaining-and-Recursive-Functions-with-JavaScript-Promise