almarc
almarc

Reputation: 1658

Chain multiple asynchronous function using promises

In this code:

new Promise((resolve, reject) => {
    DB.get(params, function(err, data) {
        if (err) reject(err)
        else resolve(data.Item)
    })
})
.then((data) => {
    let params = { Name: 'DEMO' }
    CWevents.putRule(params, function(err, data) {
        if (err) console.log("Error", err)
        else console.log("Success")
    })
})
.then(() => {
    let params = { Rule: 'DEMO' }
    CWevents.putTargets(params, function(err, data) {
        if (err) console.log("Error", err)
        else console.log("Success", data)
    })
})

The DB.get function here has a callback, but it would look awful to put multiple callbacks into each other, so I decided to use promises. I create a new promise, inside which is an asynchronous function. After it finishes running, it resolves and the first .then starts working, as desired. Then inside that first .then I have another asynchronous function that works much like the first one.

But there's no resolve/reject to run this time. So the third .then runs before the function inside second .then is finished. How can I make the third .then wait until the second one finished running? So function 1 finishes running, then function 2, then 3?

Upvotes: 0

Views: 2136

Answers (2)

Alan Lal
Alan Lal

Reputation: 147

You could wrap the CWEvents.putRule call inside a Promise. Then you can call the resolve or reject of the promise from CWEvents.putRule. This can be captured by a then or error

Your code should look like this

new Promise((resolve, reject) => {
    DB.get(params, function(err, data) {
        if (err) reject(err);
        else resolve(data.Item);
    });
})
    .then(data => { // data not needed as you are not using it in the remaining code
        let params = { Name: "DEMO" };
        return new Promise((resolve, reject) => {
            CWevents.putRule(params, function(err, data) {
                if (err) {
                    console.log("Error", err);
                    reject(err)
                } else {
                    console.log("Success");
                    resolve() // resolve(data) if you want to pass the data from CWEvents.putRule
                }
            });
        });
    })
    .then(() => {
        let params = { Rule: "DEMO" };
        CWevents.putTargets(params, function(err, data) {
            if (err) console.log("Error", err);
            else console.log("Success", data);
        });
    });

You could do the same thing in a much more readable way using async await

async function process() {
    try {
        var data = new Promise((resolve, reject) => {
            DB.get("params", function(err, data) {
                if (err) reject(err);
                else resolve(data.Item);
            });
        }); // this will return a promise to the variable data

        var response = (function processData(data) {
            let params = { Name: "DEMO" };
            return new Promise((resolve, reject) => {
                CWevents.putRule(params, function(err, data) {
                    if (err) {
                        console.log("Error", err);
                        reject(err);
                    } else {
                        console.log("Success " + data.Item);
                        resolve(data);
                    }
                });
            });
        })(await data);
        /* by using the await keyword , we can wait for the promise to be complete before moving on to the next step
          of execution.
        */

        /*
         * waiting on the response promise to complete
         */
        if (await response) {
            let params = { Rule: "DEMO" };
            CWevents.putTargets(params, function(err, data) {
                if (err) console.log("Error", err);
                else console.log("Success", data);
            });
        }
    } catch (e) {
        console.log("Error occured during operation " + e);
    }
}

process();

You can find more details about async await on MDN

Upvotes: 1

almarc
almarc

Reputation: 1658

I've found a solution. Inside a .then you can create a new Promise and return it to the next .then, like this

new Promise((resolve, reject) => {
    setTimeout(() => {resolve(1)}, 1000)
})
.then((message) => {
    console.log(message)
    return new Promise((resolve, reject) => {
        setTimeout(() => {resolve(2)}, 5000)
    })
})
.then((message) => {
    console.log(message)
    return new Promise((resolve, reject) => {
        setTimeout(() => {resolve(3)}, 1000)
    })
})

This will chain them together synchronously, so the output will be 1, 2, then 3. Without the construction it would output 1 and 3 at the same time, and then 2.

Upvotes: 0

Related Questions