Home  >  Q&A  >  body text

The importance of always catching errors in Promises

I use the @typescript-eslint/no-floating-promises rule in my project. If I write code like this, this rule will complain -

functionReturningPromise()
    .then(retVal => doSomething(retVal));

It wants me to add a catch block for this Promise. This makes sense to me if I want to add some logic in the exception handling block. However, there are many situations where I don't need it. I'm happy with the error being thrown. So, to suppress the error thrown by this rule, I ended up doing this -

functionReturningPromise()
    .then((retVal) => doSomething(retVal))
    .catch((error) => {
        throw error;
    });
Even if I don't add the catch block like above, error still gets thrown the same way (at least I see it in my console output). So I don't see the point of specifying this catch block explicitly. Did I miss something? Is there really a difference in the way error is thrown if I add/don't add the catch block?

P粉590929392P粉590929392213 days ago366

reply all(1)I'll reply

  • P粉106711425

    P粉1067114252024-03-20 17:42:08

    The commenters have all answered your question well - but to illustrate by example why this is important, imagine the following code:

    Promise.reject();
    setTimeout(() => console.log('hello'), 1000);

    This code looks pretty innocuous - there is an unhandled no-op promise rejection, and 1 second after startup the program will log 'hello'.

    In the browser - this is exactly what will happen - the browser will log an "Uncaught Promise Rejection" error, but otherwise ignore it.

    However, in NodeJS (starting with Node v15), an unhandled Promise rejection is a hard error - meaning the process will exit when the error is detected!

    You can verify this by running the code in the terminal (-e means "evaluate and run this code string")

    $ node -e "Promise.reject(); setTimeout(() => console.log('hello'), 1000)"
    node:internal/process/promises:288
                triggerUncaughtException(err, true /* fromPromise */);
                ^
    
    [UnhandledPromiseRejection: This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). The promise rejected with the reason "undefined".] {
      code: 'ERR_UNHANDLED_REJECTION'
    }
    
    Node.js v18.12.1

    You can see that 'hello' is never printed because the process terminated before 1 second!

    To verify that things are working as expected, you can change .reject to .resolve:

    $ node -e "Promise.resolve(); setTimeout(() => console.log('hello'), 1000)"
    hello

    So if you are writing a NodeJS application using any LTS supported version, then you should definitely handle errors, otherwise you will run the risk of unexpected crashes.

    If your code only runs in the browser, you might be wondering whether you should handle failures - after all, your users aren't looking at the console, so they won't know anything bad happened, so who cares? ? From a "code only" perspective, you're correct - however, your users want feedback from their application when something goes wrong.

    Imagine the following scenario - your Promise tracks the results of an API call that submits some data entered by the user in your application. If the API call fails for some reason, your application should respond appropriately and tell the user something went wrong.

    Alternative ways of handling it could mean that your app displays an infinite loading spinner, or that the user thinks their data was submitted successfully when it actually wasn't. Either way - it's a very bad and broken user experience!

    Finally do something like .catch(e => { throw e }) where you don't actually handle the error. Of course, this code will silence the linter - but all you're doing is creating a new, rejected promise, which will be logged to the console. Instead, you should connect the error to your application's UI somehow, something as simple as .catch(e => {alert(e); throw e }) would be better.

    reply
    0
  • Cancelreply