Skip to main content

JavaScript Asynchronous

JavaScript Promise Errors

Written by Published

catch handles a rejected promise, and finally runs whatever happened.

An error inside a promise does not crash the program; it rejects the promise.

If nothing catches it, the browser reports an unhandled rejection.

Example

Example

javascript

Promise.reject(new Error("no network"))
  .catch(function (error) {
    console.log("caught: " + error.message);
  });

The output is caught: no network.

Handling Failure

catch runs when the promise, or any step before it, fails.

finally runs either way and receives no value.

Throwing inside a then rejects the promise it returns.

Syntax

Syntax

javascript

promise
  .then(handler)
  .catch(handleError)
  .finally(cleanUp);

catch is shorthand for then(null, handler).

Throwing Inside a Handler

A thrown error becomes a rejection, so the catch picks it up.

Example

Example

javascript

Promise.resolve()
  .then(function () {
    throw new Error("something broke");
  })
  .catch(function (error) {
    console.log(error.message);
  });

The output is something broke.

finally Always Runs

It is for cleanup, like hiding a loading spinner.

It does not change the value passing through.

Example

Example

javascript

Promise.reject("failed")
  .catch(function (reason) {
    console.log("handled " + reason);
  })
  .finally(function () {
    console.log("cleaned up");
  });

The output is handled failed then cleaned up.

catch Placement Matters

A catch only covers the steps above it.

Putting it at the end is almost always what you want.

Example

Example

javascript

Promise.reject("early failure")
  .catch(function (reason) {
    return "recovered from " + reason;
  })
  .then(function (value) {
    console.log(value);
  });

Because the catch came first, the then still runs.

Unhandled Rejections

A rejection with no catch is reported by the browser as an error.

Always end a chain with a catch.

Example

Example

javascript

Promise.reject("ignored")
  .catch(function (reason) {
    console.log("handled properly: " + reason);
  });

Removing the catch here would log an unhandled rejection warning.

Error Objects Carry More

Rejecting with an Error gives a message and a stack trace.

Example

Example

javascript

Promise.reject(new Error("bad id"))
  .catch(function (error) {
    console.log(error instanceof Error);
    console.log(error.message);
  });

Rejecting with a plain string works but tells you less.

Complete Example

Complete Example

html

<!DOCTYPE html>
<html>
<head>
  <title>JavaScript Promise Errors</title>
</head>
<body>

  <h1>Promise Errors</h1>

  <p id="out">Loading...</p>

  <script>
    function loadUser(id) {
      return new Promise(function (resolve, reject) {
        setTimeout(function () {
          if (id > 0) {
            resolve("Ada");
          } else {
            reject(new Error("invalid id"));
          }
        }, 500);
      });
    }

    loadUser(0)
      .then(function (name) {
        document.getElementById("out").textContent = "Welcome, " + name;
      })
      .catch(function (error) {
        document.getElementById("out").textContent = "Failed: " + error.message;
      })
      .finally(function () {
        console.log("request finished");
      });
  </script>

</body>
</html>

Try It Yourself

Run the above example in the Try It Editor.

Try a valid id:

Change loadUser(0) to loadUser(1) and watch the other branch run.

Important Points

  • catch handles a rejection from any earlier step.
  • Throwing inside a handler rejects the promise.
  • finally runs either way and is for cleanup.
  • A catch only covers what comes before it.
  • Always end a chain with a catch.

Conclusion

Promise error handling is one catch at the end of the chain.

Rejecting with an Error object gives you far more to work with.

An unhandled rejection is a bug, not a warning to ignore.