简体   繁体   中英

await with try/catch and nested promises

Perhaps a bit of a dumb question but should I catch the promise within the method entitled "actionTwo()" ? What is best practice?

async actionOne(req, res, next) {
    try {
        await this.actionTwo();
    } catch( error ) => {
       // catch the error
    }
}

async actionTwo(req, res, next) {
    return new Promise( function( resolve, reject ) {
        // do something
        resolve()
    })
    .catch( error ) {
        // Do I need this catch statement???
        reject( error )
    }
}

Catch the error in whatever function can handle the error. This may be one function, or both functions, or neither function.

In your example, if actionTwo needs to do something whenever it encounters an error (for example, log that actionTwo failed), then you should indeed catch inside of it. But if actionTwo itself doesn't need to do anything particular when it encounters an error, don't .catch inside it, and instead just return the rejected Promise so that its consumer (here, actionOne ) can handle the error.

If actionOne can see the error and do something useful as a result (eg, log that actionOne failed, or render an error page, or something like that), then actionOne should catch the error. Otherwise, there's not much use to catching the error, and you should just return the actionOne Promise (automatically created by the async function) for the consumer of asyncOne to handle.

Ultimately, all errors should be caught somewhere , else you'll get unhandled rejections.

Keep in mind that if a called function needs to handle an error, and its consumer needs to see and handle the error too, the called function will have to re-throw the error in its catch , eg:

async actionOne(req, res, next) {
    try {
        await this.actionTwo();
    } catch( error ) => {
       // catch the error
    }
}

async actionTwo(req, res, next) {
    return new Promise( function( resolve, reject ) {
        // do something
        resolve()
    })
    .catch( error ) {
        // handle error
        throw error;
    }
}

Usually no, actionTwo wouldn't catch rejections, it would pass them on to its caller (which in turn might pass them to its caller, etc.).

At the top level, where you no longer have an async function, you usually catch errors and report them in some appropriate way.

Obviously, there are exceptions to this rule (no pun intended). If actionTwo can meaningfully convert a rejection into a fulfillment, then yes it would make sense for it to do so.


Note that the actionTwo in the question either shouldn't be async , or shouldn't use new Promise , depending on what "do something" is.

In the following:

  • I'll call "do something" doSomething();
  • Based on the question, actionOne and actionTwo are methods in an object literal or class definition, so I'll use that form below

If doSomething() returns a promise, then actionTwo would look like this in the normal case:

actionTwo() { // No `async`
    return doSomething();
}

or

async actionTwo() {
    const x = await doSomething();
    // ...do something with `x`...
    return x;
}

This form is also fine:

async actionTwo() { // With `async`
    return doSomething();
}

...though unnecessary. It used to introduce one extra async "tick" (which was usually harmless), but that was recently improved in the spec and we can expect JavaScript engines to adopt the change soon.

If doSomething is an old-fashioned callback-style asynchronous function, then actionTwo would typically look like this:

actionTwo() {
    return new Promise((resolve, reject) {
        doSomething(function() {
            if (/*...the action failed...*/) {
                reject(new Error(/*...with failure information...*/));
            } else {
                resolve(/*...with the result...*/);
            }
        });
    });
}

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