SoFunction
Updated on 2025-04-06

Detailed explanation of error capture of Promise in JavaScript

We need to accurately capture errors in asynchronous tasks so that we can know where the errors are

If you don’t understand Promise and trycatch enough, many times, errors in Promise cannot be caught. This article will discuss these situations

try catch

try catchOnly errors in the current context can be captured, that is, only synchronization tasks can be captured, as follows:

try {
    throw "The program has encountered some errors";
} catch(e) {
    (e)
}
// The console will output: Some errors encountered in the program execution

This is good, the error is caught, and we can handle process errors in the program;

However, for asynchronous tasks, trycatch appears powerless and cannot correctly catch the error:

try {
    setTimeout(() => {
      throw "The program has encountered some errors"  
    })
} catch(e) {
    (e);
}
// Console output: Uncaught program execution encountered some errors;

Or this:

try {
    ('The program was running some errors');
} catch(e) {
    (e);
}
// Console output: Uncaught (in promise) Some errors encountered in the execution of the program

None of the above codes catch the error normally because:What trycatch always catches synchronization error

What is a synchronization error?

When an error occurs in the same task queue in an event loop, it is a synchronization error for the context in which the task is located.

setTimeoutandPromiseCallback functions registered from different task sources will be placed in different task queues.

  • Tasks in setTimeout will be placed in macro tasks

  • Tasks in Promise will be placed in micro-tasks

    • Expand: setTimeout is a task initiated by the host browser and is usually placed in a macro task.
    • Promise is a task initiated by the JS engine and will be placed in micro-tasks

In the first event loop, the JS engine will perform the entire script code as a macro task. After the execution is completed, it will detect whether there are micro tasks in this loop. If it exists, it will read and execute all micro tasks from the task queue of the micro task in turn, then read the task execution in the task queue of the macro task, and then execute all micro tasks. This loop is like this.

The execution order of JS is the continuous switching of macro tasks-micro tasks in each event loop.

See againsetTimeoutThe error thrown in, this error is no longer presenttrycatchThe event loop is in, so this is an asynchronous error and cannot betrycatchCaptured.

Similarly, although () is executed synchronously here, the content of reject here is in another micro-task loop, fortrycatchIt is not synchronous in terms of this, so neither of these errors can be caught.

To understand, you must first understand its return value. The return is a Promise object. Please note:It's a Promise object

The Promise object is a legal object at any time. It is neither an error nor an exception. Therefore, in any implementation, it is directly directed to or a call that returns the Promise object.try catchIt's meaningless, a normal object can never trigger catch capture.

Suppose we have the following code:

function getData() {
    ('I encountered some errors');
};
function click() {
    try {
        getData();
    } catch(e) {
        (e);
    }
}
click(); // We simulate click events in business scenarios// Console output: Uncaught (in promise) Some errors were encountered

Promise has thrown an error through reject, whytry catchCan't be captured?

First of all, you need to know whether an error can be caught for a function. You can try to replace the return value of the function call with the function call to see if it is an error.

The above getDate() call will be replaced withundefined

For a function call without explicit return, its return value is alwaysundefined, so the code is as follows:

function click() {
    try {
        undefined;
    } catch(e) {
        (e);
    }
}

Those who understand the basics of js must know that this is not an exception. This code will be executed normally and will not go into the catch.

There may be another way of thinking, which is toGo back, and the code becomes:

function getData() {
  return ('I encountered some errors');
};
function click() {
    try {
        getData();
    } catch(e) {
        (e);
    }
}
click();

Returns a Promise object, which is an object, not an error. So intry catchAfter completing the getData() call in the , a Promise object will appear here. This object is a very normal object and will not be caught by catch, so thistry catchStill invalid.

So, another idea emerged: the catch method of Promise is used to capture the call, so the code becomes:

function getData() {
  return ('I encountered some errors');
};
function click() {
    try {
        getData().catch();
    } catch(e) {
        (e);
    }
}
click();

This works, rejext errors can be caught, but this is nottry catchThe credit is the internal digestion of the Promise, so heretry catchStill meaningless.

Solve Promise exception capture

Promise exception is the most common asynchronous exception. The internal errors are basically wrapped into Promise objects and passed. Therefore, there are two overall ideas for solving Promise asynchronous capture:

  • Internal digestion using Promise's catch method;
  • Use async and await to convert asynchronous errors into synchronization errors and then catch them by try catch

In principle, the error thrown in the Promise constructor, or the error thrown in then, whether it is runtime or actively thrown through throw, can be caught by the catch.

as follows:

function getData() {
    ('An error occurred here').catch();
}
​
function click() {
    getData();
}
​
click();

Or it can be captured at the call, but this requires that the called function can return the Promise object;

function getData() {
    return ('There is some error in the program');
}

function click() {
    getData().catch();
}
click();

Both of the above solutions are feasible. In fact, it is recommended to return both Promise when the business logic allows it to be passed up, and at the same time cooperate with **unhandledrejection** for the bottom line.

async await asynchronous to synchronous

Using async and await can semantically turn an asynchronous function call into synchronous execution effect, so that we can use try catch to handle it uniformly.

For example:

function getData() {
    return ('The program error occurred');
}
async function click() {
    try {
        await getData();
    } catch(e) {
        (e);
    }
}

click();

It should be noted that if the getData method does not write return, then the Promise object cannot be passed up, and the await called waits for an expanded undefined, and the error processing cannot be performed.

Things to note

If a function internally processes a Promise asynchronous object, in principle its processing result should also be a Promise object. For scenes where error capture is required, the Promise object should always be passed up through return.

Bottom-of-the-box plan

Generally speaking, if the synchronization error is not captured, the event loop where the error is located will terminate, so there are no errors caught in the development stage, so it is necessary to use a method to provide a guarantee.

For synchronization errors, you can definePerform a guaranteed treatment or use('error', errHandler)To define the guarantee function.

For Promise exceptions, you can use it synchronouslyor('unhandledrejection', errHandler)To define the guarantee function.

Let's discuss the difference between the second parameter and method in the then method

What is the difference between the second parameter of then in Promise and catch?

  • reject is used to throw an error, and it belongs to the Promise method
  • catch is used to handle exceptions, and belongs to the method of Promise instance.
  • the difference

    The main difference is that if an exception is thrown in the first function of then, the subsequent catch can be caught, but the second parameter of then cannot be caught.

    The second parameter of then and the catch capture information will follow the principle of proximity. If an error is reported within the promise and the error is thrown by the reject, and the second parameter of then and the catch method exists, only then the second parameter of then can be captured. If the second parameter of then does not exist, the catch method will be captured.

Question: How can you know which method then report an error in the continuous call?

new Promise((resolve,reject) => {
    setTimeout(() => {
        resolve(1);
    }, 1000)
}).then(res => {
    (res);
    return new Promise((resolve,reject) => {
        reject('The first then method reported an error');
    })
}).then(res => {
    (res);
    return new Promise((resolve,reject) => {
		reject('The second method reported an error');
    })
}).catch(err => {
    (err);
})

Summarize

This is all about this article about Promise error capture in JavasScript. For more related JS Promise error capture content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!