0

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?

4
  • Can you add a resolve() and reject() instead of the console.log()s? Commented Oct 22, 2019 at 16:47
  • No, resolve is only defined for the first Promise() function. The .then's don't have a resolve() function. Commented Oct 22, 2019 at 16:50
  • To chain, ALL your asynchronous operations need to return promises. Then you can return the promise from the .then() handler and they will sequence properly and errors will work properly. Step 1, promisify all your asynchronous operations. util.promisify() is your friend here. Or, most databases these days have a built-in promise interface you can use instead of the callback interface. Commented Oct 22, 2019 at 17:48
  • Search promise chaining. You should take your DB and CWevents implementation into separate functions and make them return a promise. In this way your code would be much cleaner. Commented Oct 23, 2019 at 4:32

2 Answers 2

1

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

Sign up to request clarification or add additional context in comments.

Comments

0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.