简体   繁体   中英

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).

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 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

I believe what's missing from your second codeset is returning the result. Not only does your inner promise not "return p2" but you're not using the resolve/reject functions you're generating. For starters, I would avoid creating new Promise objects as a way of resolving other ones - usually, this can be done through a better understanding of the promise libraries (using either then or all ).

// this function returns a 2-long array (inside a promise), so you may want to change
// the calling syntax
var p21 = function() {
    // Do not "return promise" - we create a new one just by calling "then()"
    //return new Promise(function (resolve, reject) {
    return p1().then(function (data) {
        return p2().then(function(data2) {
            return [data, data2];
        });
    });
};

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