简体   繁体   中英

Serialized Execution of an Array of Promise Chains in Bluebird

I am trying to build an array of Promises chains and get them to execute in order. Each chain completes before the next entry in the array executes. For example: [connect1, connect2, connect3] where each "task" contain a chain of some number of steps.

One of the big problems I have is being able to build the chain and add it to the array--since it has already began execution.

Some of the test code I have been toying with is here:

function step1() {
    return new Promise(resolve => {
        // Normally something asnyc here
        console.log("step1:", this);
        resolve();
    });
}
function step2() {
    return new Promise(resolve => {
        // Normally something asnyc here
        console.log("step2:", this);
        resolve();
    });
}
function step3() {
    return new Promise(resolve => {
        // Normally something asnyc here
        console.log("step3:", this);
        resolve();
    });
}

function promiseSeq( tasks, state ) {

    let current = Promise.resolve();
    for (let k = 0; k < tasks.length; ++k) {
        var taskWithState = tasks[k];
        if (typeof state !== 'undefined') {
            taskWithState = taskWithState.bind(state);
        }
        current = current.then(taskWithState);
    }
    return current;

}

function buildChain(idx) {

    // Build the connection chain (with state)
    //------------------------------
    var s = { conn: idx }; // some state
    var q = [ step1, step2, step3 ];
    return promiseSeq(q, s);
}

function streamConnect() {

    // Build array of chains
    //------------------------------
    var q = [ ];
    q.push(buildChain(1)); // e.g. connect1
    q.push(buildChain(2)); // e.g. connect2
    q.push(buildChain(3)); // e.g. connect3

    var p = Promise.each(q, function(f) {return ( f )});

    // Process promises...
    p.then(function()     {console.log("done")})
     .catch(function(err) {console.error("catch:",err)})

    return;

}

Once I have the chains for each "task" in the array, I want to execute the chain in order. So my goal is to get the output to be:

step1: Object {conn: 1}
step2: Object {conn: 1}
step3: Object {conn: 1}
step1: Object {conn: 2}
step2: Object {conn: 2}
step3: Object {conn: 2}
step1: Object {conn: 3}
step2: Object {conn: 3}
step3: Object {conn: 3}

Instead using my code I see:

step1: Object {conn: 1}
step1: Object {conn: 2}
step1: Object {conn: 3}
step2: Object {conn: 1}
step2: Object {conn: 2}
step2: Object {conn: 3}
step3: Object {conn: 1}
step3: Object {conn: 2}
step3: Object {conn: 3}

I am very green when it comes to Promises and I am trying to understand ( in no specific order): 1. Why the promise execution appears to interleave (all step1's done, then step2, etc)? 2. How can I get serialized execution line my expected output above? 3. Can the chains be setup in a deferred manner? I saw my line current = current.then(taskWithState); ultimately calls async.invoke with Bluebird, but I didn't see a way to avoid this.

Any advice or help would be much appreciated.

Your buildChain() function EXECUTES your operations. It starts running them immediately.

So, this code:

var q = [ ];
q.push(buildChain(1)); // e.g. connect1
q.push(buildChain(2)); // e.g. connect2
q.push(buildChain(3)); // e.g. connect3

Starts running all three chains right away. So, you have three promise chains running in parallel, not in sequence.

FYI, this line of code should have been an interesting clue:

var p = Promise.each(q, function(f) {return ( f )});

Because you're not actually doing anything when Promise.each() calls its callback. As such, you have not given it any control over your operations. They've already been started before Promise.each() even runs.


You can use Promise.each() to solve this, but you need to use it as intended. It expects you to pass it an array of something and an iterator that operates on the items in the array. You aren't doing anything like that. You're passing it an array of promises that have already started executing.


You can fix it by changing streamConnect() to this:

function streamConnect() {

    var q = [1,2,3];

    var p = Promise.each(q, function(item) {
        return buildChain(item);
    });

    // Process promises...
    p.then(function() {console.log("done")})
     .catch(function(err) {console.error("catch:",err)})

    return;

}

This doesn't start executing each chain UNTIL called by Promise.each() .

Working demo: https://jsfiddle.net/jfriend00/3ce0ceuy/

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM