This might sound weird to you, the first thing that comes to mind is: 'Eslint will tell me to remove the await, there is no need for an await after a return'
But the case is a different when we wrap our promise in a try/catch
.
async function foo() {
try {
return await waitAndMaybeReject();
} catch (e) {
return 'caught';
}
}
This also applies when we don't need to return resolved value of the promise, we always need to await it if the returned promise is inside a try/catch
and we want to catch the error.
By returning a promise, we’re deferring its result, so our catch block never runs.
This also happens, when not awaiting a promise (regardless if we return or not).
Only outside of try/catch blocks,
return await
is redundant. There’s even an Eslint rule, but this rule allows a return if it's intry/catch
.
Bonus🔥
If you want to print something after a return statement, instead of temporaraly creating a variable, printing and then returning, like this:
async function foo() {
const res = await fetch();
console.log('after fetch')
return res;
}
We can wrap the return with a try and finallly (unless you need to print the resolved value of the promise of course), like so:
async function foo() {
try {
return await fetch();
} finally {
console.log('after fetch')
}
}
Top comments (17)
In my opinion, you should almost never return a promise from an async function. You should
return await
instead. Not only does that cover this case naturally, it also improves async stack traces for debugging.Returning a promise from an async function is still needed if you want to run several operations in parallel, isn't it? That optimization comes up fairly frequently in my code when I tune its performance.
Why can you not run multiple functions in parallel if they're awaited? 🤔
That's right, that's a good use case for returning a promise without
await
, thanks for the clarification 🙏An async function, definitionally and per spec, always returns a
Promise
.Working proof: replit.com/@manchicken/What-async-...
I think it’s pretty common to call another async function at the end of your async function and return the result. As in the example. In that case there’s no way around it.
Interesting, Are you disabling the Eslint rule then?
The rule definition is as follows, personally I think it's rather dangerous as the most likely effect of applying it is that exceptions end up being incorrectly handled. Now this happens because initially there is no try/catch so eslint complains about the await and then the developer removes it and later adds a try/catch block for errors - if it had been there from the start then the await would not have been linted.
Disallows unnecessary return await (no-return-await)
Inside an async function, return await is useless. Since the return value of an async function is always wrapped in Promise.resolve, return await doesn’t actually do anything except add extra time before the overarching Promise resolves or rejects. This pattern is almost certainly due to programmer ignorance of the return semantics of async functions.
I agree, thanks for the awesome explanation Mike!
Async await is more convenient than Promise chains, but I don't see why you wouldn't use Promise.catch in the example.
You could, this example is pretty simple so you're right, but for more complex logic try and catch is usually more convinient
Great post! It was short, easy to understand, and easy to see the advantage of organizing the code you propose.
Thank you Martin! I appreciate it :)
I could not fully understand the purpose if this blog.
Yeah I don't get the pros and cons of using it. I didn't even know you could do that, and I'm unsure exactly why I would or would not want to in the context of a try block, based on reading this blog post.
The main pro is being able to catch the error. I don’t see a con.
This is a specific use case for when you return a promise
To share a bug I had where I didn’t use await when I returned a promise and I couldn’t understand why my console log in the catch didn’t print