简体   繁体   中英

Cannot figure out how to chain nested promise with Q

I'm new into node.js and promise (Q), so please be kind. I want to chain nested promises with his executing parent chain and i can't find how to.

I've made a toy script to illustrate my pb, you can launch it with node.js :

var Q = require("q");

function init() {
    return {nbIn: 0, nbOut: 0, stop: false};
}

function fn1(ctx) {
    var deferred = Q.defer();

    console.log("fn1:" + JSON.stringify(ctx));
    setTimeout(function() {
        console.log("fn1: resolve");
        deferred.resolve(ctx);
    }, 1000)

    return deferred.promise;
}

function sub1(ctx) {
    var deferred = Q.defer();

    console.log("sub1:" + JSON.stringify(ctx));
    setTimeout(function() {
        ++ctx.nbIn;
        console.log("sub1: resolve");
        deferred.resolve(ctx);
    }, 1000);

    return deferred.promise;
}

function sub2(ctx) {
    var deferred = Q.defer();

    console.log("sub2:" + JSON.stringify(ctx));
    setTimeout(function() {
        ++ctx.nbOut;
        if(ctx.nbOut === 3) {
            console.log("sub2: resolve");
            ctx.stop = true;
            deferred.resolve(ctx);
        }
        else {
            console.log("sub2: promise");
            return sub1(ctx).then(sub2);
        }
    }, 1000);

    return deferred.promise;
}

function fn2(ctx) {
    console.log("fn2:" + JSON.stringify(ctx));
    return sub1(ctx).then(sub2);
}

function fn3(ctx) {
    console.log("fn3:" + JSON.stringify(ctx));
}

Q.fcall(init).then(fn1).then(fn2).then(fn3);

It display:

fn1:{"nbIn":0,"nbOut":0,"stop":false}
fn1: resolve
fn2:{"nbIn":0,"nbOut":0,"stop":false}
sub1:{"nbIn":0,"nbOut":0,"stop":false}
sub1: resolve
sub2:{"nbIn":1,"nbOut":0,"stop":false}
sub2: promise
sub1:{"nbIn":1,"nbOut":1,"stop":false}
sub1: resolve
sub2:{"nbIn":2,"nbOut":1,"stop":false}
sub2: promise
sub1:{"nbIn":2,"nbOut":2,"stop":false}
sub1: resolve
sub2:{"nbIn":3,"nbOut":2,"stop":false}
sub2: resolve

I would like to chain the last line sub2 with fn3 .

Any help appreciated, Thanks.

 setTimeout(function() { … return sub1(ctx).then(sub2); }, …) 

Here you're trying to return from an asynchronous plain callback. You cannot do that, the result will be lost as setTimeout does not care about it.

You can only return from .then() callbacks. In your case, it would look like this:

function sub2(ctx) {
    var deferred = Q.defer();

    console.log("sub2:" + JSON.stringify(ctx));
    setTimeout(function() {
        deferred.resolve(ctx);
    }, 1000);

    return deferred.promise.then(function(ctx) {
        ++ctx.nbOut;
        if (ctx.nbOut === 3) {
            console.log("sub2: resolve");
            ctx.stop = true;
            return ctx;
        } else {
            console.log("sub2: promise");
            return sub1(ctx).then(sub2);
        }
    });
}

You also can see that you're always using Q.defer together with a setTimeout now. You should make a helper function for that which returns a promise, and use deferreds as seldom as possible .

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