JavaScript best practice: use return await

A common pattern is to call an async function and return its result:
const helloWorld = async () => {
return await asyncHello("World");
}
// Hello World
Why the await
? It would work exactly the same without it, so it's just taking up space.
Yes, but: let's add a try..catch
block around it:
try {
return await asyncHello("World");
}catch(e) {
return "Whops";
}
// Whops
It works as expected: if the called function throws an error (rejects its Promise) then the catch
block will run.
But now there is a difference:
try {
return asyncHello("World");
}catch(e) {
return "Whops";
}
// Uncaught Error
Why didn't the try..catch
handle the Error? It was thrown from inside the block, yet it still wasn't caught.
await
stops the function execution. So in the first case (return await
) the helloWorld
function is still running, the execution is inside the try..catch
block.
But in the second case the function is already finished and did not stop in the try..catch
. It returned the Promise the asyncHello
returned without any additional error handling.
This happens not just with try..catch
but also for cleanups that use the try..finally
block:
export const withTempDir = async (fn) => {
const dir = await createTempDir();
try {
return await fn(dir);
}finally {
await fs.rm(dir, {recursive: true});
}
};
Without the await
the temporary directory would be deleted when the fn
runs. But with the await
it waits for the fn
to finish before cleaning up.