Reputation: 1606
i.e.
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.
Upvotes: 33
Views: 40731
Reputation: 19301
Using one try/catch block containing multiple await
operations is fine when waiting for promises created on the right hand side of the await
unary operator:
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.
Uncaught Rejection warning
If code await
s promises that were not created by the await
operator's argument expression, and don't have a rejection handler, the promises won't have a rejection handler before the await
operator applied to them is executed at runtime.
If the try/catch block is triggered before await
adds a handler to such promises, and they reject, an uncaught rejection error occurs. Thanks to @EyolRoth for this caveat, Please see his answer for a case example.
Recommendation: consider carefully if you need to await a promise that was created earlier and doesn't have an error handler. Then examine
await
's operand expression, orUpvotes: 48
Reputation: 138
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 i.e, 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.
Upvotes: -1
Reputation: 4019
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; i.e, 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; i.e, 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.
Upvotes: 13