Await vs return vs return await
There are some differences between await,return, and return await when writing asynchronous functions, and it is important to choose the right way from them. Let’s start with the following asynchronous function:
async function waitAndMaybeReject(){
// Wait 1 second
await new Promise(resolve= > setTimeout(resolve, 1000));
Flip a coin
const isHeads = Boolean(Math.round(Math.random()));
if(isHeads) return 'yay';
throw Error('Boo! ');
}
Copy the code
The above function waits one second to return a promise, and then has a 50% chance of successfully returning yay or raising an error. Let’s use it in a few slightly different ways.
If you want to try to verify the result by running the following code, create async function to call foo with await.
Direct call
async function foo() {
try{
waitAndMaybeReject();
}catch(e){
return 'caught'; }}Copy the code
Here, if foo is called, the return promise is always resolved, always undefined, and there is no waiting. Since we have no await, or return the result of waitAndMaybeReject (), we cannot react to it in any way. Code like this is usually wrong.
Awaiting
async function foo(){
try{
await waitAndMaybeReject();
}catch(e){
return 'caught'; }}Copy the code
Here, if foo is called, the return promise will always wait one second and then result in either an Resolved state with a value of undefined or an resolved state with a value of “Caught”. Since we wait on the return of waitAndMaybeReject(), its rejection is returned and thrown, and the catch block is executed. However, if waitAndMaybeReject() executes without an error, we still can’t do anything with its return value.
Returning
async function foo() {
try {
return waitAndMaybeReject();
}
catch (e) {
return 'caught'; }}Copy the code
At this point, if foo is called, the return promise will always wait 1 second and then result in either a resolved state with a value of “yaa” or a reject state, throwing an Error(‘Boo! ‘). With the return waitAndMaybeReject() line, we pass its return directly, so our catch block never executes.
Return-awaiting
If you want to get resolved state with the correct return value in the try block and catch the exception in the catch, the right choice is return await.
async function foo() {
try {
return await waitAndMaybeReject();
}
catch (e) {
return 'caught'; }}Copy the code
Here, if foo is called, the return promise will always wait one second, and then the result will either be resolved with a value of “yay” or resolved with a value of “Caught” because we’re waiting for the result of waitAndMaybeReject(), So its exception rejecttion will be returned and thrown, and the catch block will execute. If waitAndMaybeReject() executes without error, its result is returned.
If you’re still confused by the above, it might make sense to break the code into two steps:
async function foo() {
try {
// Wait for the result of waitAndMaybeReject() to resolve,
// Assign fullfill to fullfilledValue:
const fulfilledValue = await waitAndMaybeReject();
// If waitAndMaybeReject() reject,
// Our code throws an exception and goes into the logic of the catch block.
// Otherwise, the code will continue to run the following statement:
return fulfilledValue;
}
catch (e) {
return 'caught'; }}Copy the code
Note: It is superfluous to have a return await inside a block other than a try/catch (as mentioned above, just return), and even Eslint has rules to detect this, but Eslint allows this inside a try/catch block.