简体   繁体   中英

Can I use multiple 'await' in an async function's try/catch block?

ie

async asyncfunction(){
  try{
    await method1();
    await method2();
  }
  catch(error){
    console.log(error);
  }
}

Given method1() and method2() are asynchronous functions. Should there be a try/catch block for each await method? Is there an even cleaner way to write this? I'm trying to avoid '.then' and '.catch' chaining.

Using one try/catch block containing multiple await operations is fine.

The await operator stores its parent async functions' execution context and returns to the event loop. Execution of the await operator resumes when it is called back with the settled state and value of its operand.

Upon resumption, await restores the previously saved execution context and returns the operand promise's fulfilled value as the result of the await expression, or throws the rejection reason of a rejected operand.

The try/catch block invocation is part of the execution context both before and after being saved and restored. Hence multiple await operations do not disturb the behavior of an outer try block they share. The catch block will be invoked with the rejection reason of any promise awaited in the try block that is rejected.

While @traktor answer is correct, I want to add a very important caveat.

The following code snippet is unsafe:

async function foo() {
  try {
    const p1 = method1();
    const p2 = method2();

    await p1;
    await p2;
  } catch (e) {
    console.log(e);
  }
}

If both promises are rejected, the code will result in UnhandledPromiseRejectionWarning in NodeJS, potentially killing the process if the option --unhandled-rejections is set to throw (which will become the default behavior from Node 15).

Why is this happening?

In the original code of the question, the async methods are invoked sequentially; ie, if the first method fails (promise rejected), the second method is never invoked.

However, the code from the beginning of this answer invokes both of the async methods in parallel; ie, the second method is invoked regardless if the first method succeeds or not.

In this scenario, only the await on the promise of the second method is conditioned on the success of the first method. Meaning, if the first method fails, the promise of the second method (which has already started) is never awaited, so if it fails too, it will result in an handled promise rejection.

How to overcome this behavior?

Assuming we wish to handle both rejections in the same way, we can use Promise.all :

try {
  const p1 = method1();
  const p2 = method2();
  
  await Promise.all([p1, p2]);
} catch (e) {
  console.log(e);
}

Only the first promise to be rejected will "trigger" the catch clause, while the second will be silently ignored without crashing the process.

Using Async.js Library Let's talk about working with the async.js library in order to avoid callback hell.

As per the official website of async.js : Async is a utility module which provides straight-forward, powerful functions for working with asynchronous JavaScript.

Async.js provides near about 70 functions in total. For now, we will discuss only two of them ie, async.waterfall() and async.series().

async.waterfall() This method is useful when you want to run some tasks one after the other and then pass the result from the previous task to the next task. It takes an array of functions "tasks" and a final "callback" function that is called after all functions in "tasks" array have completed or a "callback" is called with an error object.

async.js library

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