Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Correct Try...Catch Syntax Using Async/Await

I like the flatness of the new Async/Await feature available in Typescript, etc. However, I'm not sure I like the fact that I have to declare the variable I'm awaiting on the outside of a try...catch block in order to use it later. Like so:

let createdUser try {     createdUser = await this.User.create(userInfo) } catch (error) {     console.error(error) }  console.log(createdUser) // business // logic // goes // here 

Please correct me if I'm wrong, but it seems to be best practice not to place multiple lines of business logic in the try body, so I'm left only with the alternative of declaring createdUser outside the block, assigning it in the block, and then using it after.

What is best practice in this instance?

like image 315
freedomflyer Avatar asked Jun 20 '17 22:06

freedomflyer


People also ask

Can we use try catch with async await?

We can use try... catch (in combination with async functions) and the . catch() approaches to handle errors for asynchronous code. When returning a promise within a try block, make sure to await it if you want the try...

What block of code do we use to catch errors with async await?

async and await We can even use a try... catch block for error handling, exactly as we would if the code were synchronous. You'll probably use async functions a lot where you might otherwise use promise chains, and they make working with promises much more intuitive.

How do you catch error in async await react?

The last way to handle an error with async/await is called a higher order function. We have talked about this a couple of times now. A higher order function is a function that returns another function. The way it works is you go ahead and define all of your functions, just as if you were never to have any errors.


Video Answer


2 Answers

It seems to be best practice not to place multiple lines of business logic in the try body

Actually I'd say it is. You usually want to catch all exceptions from working with the value:

try {     const createdUser = await this.User.create(userInfo);      console.log(createdUser)     // business logic goes here } catch (error) {     console.error(error) // from creation or business logic } 

If you want to catch and handle errors only from the promise, you have three choices:

  • Declare the variable outside, and branch depending on whether there was an exception or not. That can take various forms, like

    • assign a default value to the variable in the catch block
    • return early or re-throw an exception from the catch block
    • set a flag whether the catch block caught an exception, and test for it in an if condition
    • test for the value of the variable to have been assigned
      let createdUser; // or use `var` inside the block   try {       createdUser = await this.User.create(userInfo);   } catch (error) {       console.error(error) // from creation   }   if (createdUser) { // user was successfully created       console.log(createdUser)       // business logic goes here   } 
  • Test the caught exception for its type, and handle or rethrow it based on that.

      try {       const createdUser = await this.User.create(userInfo);       // user was successfully created       console.log(createdUser)       // business logic goes here   } catch (error) {       if (error instanceof CreationError) {           console.error(error) // from creation       } else {           throw error;       }   } 

    Unfortunately, standard JavaScript (still) doesn't have syntax support for conditional exceptions.

    If your method doesn't return promises that are rejected with specific enough errors, you can do that yourself by re-throwing something more appropriate in a .catch() handler:

      try {       const createdUser = await this.User.create(userInfo).catch(err => {           throw new CreationError(err.message, {code: "USER_CREATE"});       });       …   } … 

    See also Handling multiple catches in promise chain for the pre-async/await version of this.

  • Use then with two callbacks instead of try/catch. This really is the least ugly way and my personal recommendation also for its simplicity and correctness, not relying on tagged errors or looks of the result value to distinguish between fulfillment and rejection of the promise:

      await this.User.create(userInfo).then(createdUser => {       // user was successfully created       console.log(createdUser)       // business logic goes here   }, error => {       console.error(error) // from creation   }); 

    Of course it comes with the drawback of introducing callback functions, meaning you cannot as easily break/continue loops or do early returns from the outer function.

like image 110
Bergi Avatar answered Nov 01 '22 22:11

Bergi


Another simpler approach is to append .catch to the promise function. ex:

const createdUser = await this.User.create(userInfo).catch( error => { // handle error }) 
like image 37
nevf Avatar answered Nov 01 '22 20:11

nevf