'return await' in a try/catch
Daniel Bellmas

Daniel Bellmas @danielbellmas

About: Full-Stack Developer

Joined:
Sep 20, 2021

'return await' in a try/catch

Publish Date: Dec 9 '23
29 17

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';
  }
}
Enter fullscreen mode Exit fullscreen mode

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 in try/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;
} 
Enter fullscreen mode Exit fullscreen mode

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')
  }
} 
Enter fullscreen mode Exit fullscreen mode

Comments 17 total

  • Yeom suyun
    Yeom suyunDec 10, 2023

    Async await is more convenient than Promise chains, but I don't see why you wouldn't use Promise.catch in the example.

    • Daniel Bellmas
      Daniel BellmasDec 10, 2023

      You could, this example is pretty simple so you're right, but for more complex logic try and catch is usually more convinient

  • Shameel Uddin
    Shameel UddinDec 10, 2023

    I could not fully understand the purpose if this blog.

    • Michael Kochell
      Michael KochellDec 11, 2023

      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.

      • Daniel Bellmas
        Daniel BellmasDec 11, 2023

        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

    • Daniel Bellmas
      Daniel BellmasDec 11, 2023

      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

  • Joshua Baker
    Joshua BakerDec 10, 2023

    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.

    • Daniel Bellmas
      Daniel BellmasDec 11, 2023

      Interesting, Are you disabling the Eslint rule then?

      • Mike Talbot ⭐
        Mike Talbot ⭐Dec 14, 2023

        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.

        • Daniel Bellmas
          Daniel BellmasDec 15, 2023

          I agree, thanks for the awesome explanation Mike!

    • Brian Morearty
      Brian MoreartyDec 11, 2023

      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.

    • Martin Omander
      Martin OmanderDec 11, 2023

      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.

      • Daniel Bellmas
        Daniel BellmasDec 11, 2023

        That's right, that's a good use case for returning a promise without await, thanks for the clarification 🙏

      • Daniel Hillmann
        Daniel HillmannDec 11, 2023

        Why can you not run multiple functions in parallel if they're awaited? 🤔

        async function getWebpage(url) {
          try {
            const { data: webpage } = await axios.get(url);
        
            return webpage;
          } catch (err) {
             // a request failed
             // will make Promise.all throw
          }
        }
        const results = await Promise.all([
          getWebpage('https://google.com'),
          getWebpage('https://facebook.com')
        ]);
        // Executed in parallel
        // results[0] = google
        // results[1] = facebook 
        
        Enter fullscreen mode Exit fullscreen mode
    • Mike Stemle
      Mike StemleDec 16, 2023

      An async function, definitionally and per spec, always returns a Promise.

      Working proof: replit.com/@manchicken/What-async-...

  • Martin Omander
    Martin OmanderDec 11, 2023

    Great post! It was short, easy to understand, and easy to see the advantage of organizing the code you propose.

Add comment