Welcome to pay attention to my public account “Life Code”

In the original

Once you have a “promise”, it’s not done, it needs to be dealt with

Promise is great at error handling. When a promise rejects, the control jumps to the most recent rejection handler. This is handy in practice.

For example, the following code gets the wrong URL (there is no such site) and.catch handles the error:

fetch('https://no-such-server.blabla'// rejects

  .then(response= > response.json())

  .catch(err= > alert(err)) // TypeError: failed to fetch (the text may vary)

Copy the code

As you can see,.catch is not necessarily immediate. It may appear in one or several.then.

Or, maybe the site is fine, but the response is not valid JSON. The easiest way to catch all errors is to add.catch to the end of the chain:

fetch('/article/promise-chaining/user.json')

  .then(response= > response.json())

  .then(user= > fetch(`https://api.github.com/users/${user.name}`))

  .then(response= > response.json())

  .then(githubUser= > new Promise((resolve, reject) = > {

    let img = document.createElement('img');

    img.src = githubUser.avatar_url;

    img.className = "promise-avatar-example";

    document.body.append(img);



    setTimeout((a)= > {

      img.remove();

      resolve(githubUser);

    }, 3000);

  }))

  .catch(error= > alert(error.message));

Copy the code

Usually, this.catch does not fire at all. However, if any of the above promises are rejected (network problems or invalid JSON or whatever), then it catches it.

Implicit try catch

The Promise executor and Promise handler code have an “invisible try.. The catch. If an exception occurs, it is caught and processed as a rejection.

For example, the following code:

new Promise((resolve, reject) = > {

  throw new Error("Whoops!");

}).catch(alert); // Error: Whoops!

Copy the code

It works exactly the same way:

new Promise((resolve, reject) = > {

  reject(new Error("Whoops!"));

}).catch(alert); // Error: Whoops!

Copy the code

“The invisible try.. Catch, the executing program automatically catches the error and converts it into a rejected Promise.

This happens not only in executor functions, but also in their handlers. If we throw a. Then handler, it means a promise was rejected, so the control jumps to the most recent error handler.

Here’s an example:

new Promise((resolve, reject) = > {

  resolve("ok");

}).then((result) = > {

  throw new Error("Whoops!"); // rejects the promise

}).catch(alert); // Error: Whoops!

Copy the code

This happens with all errors, not just those caused by throw statements. For example, a programming error:

new Promise((resolve, reject) = > {

  resolve("ok");

}).then((result) = > {

  blabla(); // no such function

}).catch(alert); // ReferenceError: blabla is not defined

Copy the code

Finally. Catch catches not only explicit rejections, but also unexpected errors in the handler described above.

Rethrowing

As we have already noted,. Catch at the end of the chain is similar to a try.. The catch. We can have as many.then handlers as we want, and then use a.catch at the end to handle errors in all of them.

On a regular basis… We can analyze the error, and if we can’t handle it, we may rethrow the error. The same thing can happen with promises.

If we throw it in a. Catch, the control goes to the next nearest error handler. If we handle the error and complete normally, it will continue to the next successful one. Then the handler.

In the following example,.catch successfully handles the error:

// the execution: catch -> then

new Promise((resolve, reject) = > {



  throw new Error("Whoops!");



}).catch(function(error{



  alert("The error is handled, continue normally");



}).then((a)= > alert("Next successful handler runs"));

Copy the code

Here, the.catch block completes normally. Therefore, the next successful. Then handler is called.

In the following example, we’ll see another case of.catch. The handler (*) caught the error, but couldn’t handle it (for example, it only knew how to handle URIError), so it threw it again:

// the execution: catch -> catch

new Promise((resolve, reject) = > {



  throw new Error("Whoops!");



}).catch(function(error/ / (*)



  if (error instanceof URIError) {

    // handle it

  } else {

    alert("Can't handle such error");



    throw error; // throwing this or another error jumps to the next catch

  }



}).then(function({

  /* doesn't run here */

}).catch(error= > { / / (* *)



  alert(`The unknown error has occurred: ${error}`);

  // don't return anything => execution goes the normal way



});

Copy the code

The execution jumps from the first. Catch (*) to the next. The catch (* *).

Unhandled rejections

What happens when an error is not handled? For example, we forgot to add.catch to the end of the chain, like this:

new Promise(function({

  noSuchFunction(); // Error here (no such function)

})

  .then((a)= > {

    // successful promise handlers, one or more

  }); // without .catch at the end!

Copy the code

In the case of an error, the commitment is rejected, and execution should jump to the most recent rejection handler. But no. So the error is “stuck”. There’s no code to handle it.

In practice, just like regular unhandled errors in code, this means something is seriously wrong.

If a general error occurs, but try.. What happens if the catch doesn’t catch it? The script ends in the console with a message. A similar thing can happen with untreated rejection of commitments.

The JavaScript engine tracks this rejection and generates a global error in this case. If you run the example above, you can see it in the console.

In the browser, we can use the unhandledrejection event to catch such errors:

window.addEventListener('unhandledrejection'.function(event{

  // the event object has two special properties:

  alert(event.promise); // [object Promise] - the promise that generated the error

  alert(event.reason); // Error: Whoops! - the unhandled error object

});



new Promise(function({

  throw new Error("Whoops!");

}); // no catch to handle the error

Copy the code

Events are part of the HTML standard.

If there’s an error, but there’s no catch, the unhandledrejection handler will fire and get the event object with the error message, so there’s something we can do.

Usually this error is not recoverable, so our best solution is to notify the user of the problem and possibly report the event to the server.

In a non-browser environment such as Node. There are other ways to track unhandled errors.