1. try/catch
Try /catch is basically the one you use most often with async/await, and basically we use it to surround most asynchronous methods. Once the promise after the await keyword is rejected, an exception error is thrown.
run();
async function run() {
try {
await Promise.ject(new Error('Oops! '));
} catch (err) {
console.error(error.message); }}Copy the code
Try /catch can also handle synchronous errors, such as the following:
async function run() {
const v = null;
try {
await Promise.resolve('foo');
v.thisWillThrow;
} catch (error) {
// "TypeError: Cannot read property 'thisWillThrow' of null"
console.error(error.message); }}Copy the code
return
The problem
Does it seem like we can just mindlessly put all our logic into try/catch and be fine? Not exactly, but the following code causes unhandled Promise Rejection. The return keyword returns an error without being caught:
async function run() {
try {
Return the Promise directly instead of using the await keyword
return Promise.reject(new Error('Oops! '));
} catch (error) {
console.error(error.message); }}Copy the code
The solution here is to use return await:
async function run() {
try {
return await Promise.reject(new Error('Oops! ')); } catch (error) { console.error(error.message); }}Copy the code
The callback problem
Another problem is that a try catch does not catch callback functions. Try catch only works in a single execution environment. Here we add a try catch to the callback to catch errors:
setTimeout(funciton() {
try {
fn()
} catch (e) {
// handle error}})Copy the code
It works, but try catch happens everywhere. The V8 engine discouragestry catches in functions. Previous attempts to move a try catch to the top level to catch errors in the call stack did not work for asynchronous code.
2. Golang-style(then)
Golang style uses the. Then () method to convert a promise into a reject promise that processes the error. You can use something like if(err) to check:
async function throwAnError() {
throw new Error('Opps! ');
}
async function runAwait() {
let err = await throwAnError();
if (err){
console.error(err.message); }}Copy the code
This will throw an exception directly, because the method throws an exception, but the method itself is not caught by a try/catch. A lot of times, this happens when we use third-party libraries.
Then () solution
async function runAwait() {
let err = await throwAnError().then((a)= > null, err => err);
if (err){
console.error(err.message); }}Copy the code
The then() method waits for the promise state resolve or Reject to execute the corresponding callback, then determines the err object and processes it, so it’s essentially caught.
Return both an error and a value
async function run() {
let [err, res] = await throwAnError().then(v= > [null, v], err => [err, null]);
if (err){
console.error(err.message);
}
console.log(res)
}
Copy the code
Results:
Doing so returns an array of results and error objects by deconstruction. Reject, of course, returns null and error; If the error object that Resolved returns is null, the second will be the result.
The advantages and disadvantages
- Advantages: This mode can be handled more succinctly, while eliminating the need to write
catch
. - Disadvantage 1: This is very repetitive and requires judgment every time an asynchronous operation is performed
error
Object. - Disadvantage 2: Can’t help with processing
run
Synchronization error in method. So this approach needs to be used with caution.
3. Catch caught
Both modes can handle asynchronous errors, but for error handling, it is best to include a catch at the end of the asynchronous logic to ensure that all errors are caught. This is also a principle of treating errors collectively rather than individually.
async function run() {
return Promise.reject(new Error('Oops! '));
}
run().catch(function handleError(err) {
console.error(err.message);
}).catch( err= > {
process.nextTick((a)= > { throw errl});
})
Copy the code
Catch an error using a catch. If handleError has an error of its own, it needs to catch again, but to avoid callback hell, it terminates the process if the method has an error.
The advantages and disadvantages
- use
catch
The asynchronous method catches asynchronous errors regardless of whether or not it catches errors. - use
try/catch
Unable to avoidcatch
Itself throws an exception, and if it throws that in addition to nesting one more layertry/catch
The best thing to do is to addcatch
To make the code cleaner.
4 Global error capture
4.1 Browser global error capture
Browser global processing is basically event-driven because browsers are event-driven. Once an error is thrown, the interpreter stops execution and expands in the execution context, at which point an onError global event is thrown:
window.addEventListener('error'.function (e) {
var error = e.error;
console.log(error);
})
Copy the code
The global error handler catches any errors that occur in the execution environment, even error events for different objects, or various types of errors. This is a common way to handle errors globally.
The call stack
The call stack is very important in locating problems and can be used to handle specific errors within the processor.
window.addEventListener('error'.function (e) {
var stack = e.error.stack;
var message = e.error.toString();
if (stack) {
message += '\n' + stack;
}
var xhr = new XMLHttpRequest();
xhr.open('POST'.'/log'.true);
// Fire an Ajax request with error details
xhr.send(message);
});
Copy the code
The log allows you to see exactly what conditions triggered what errors. The call stack can also be useful when debugging. You can analyze the log and see what conditions triggered the error.
Note:
Cross-domain scripts do not see errors. In JS, error messages are only allowed in the same field.
Personal ideas
More often than not, the code throws an exception, and we care more about what the value of a variable is at run time and whether the value of the variable caused the error, so it’s more important to print out more information about the call.
4.2 Node.js global error capture
Node.js’s own exception handling is much more complicated because it involves processes or threads throwing exceptions.
Koa-based global error handling
Nodejs is an error-first asynchronous processing mechanism where the underlying net module’s LISTEN method is called and a callback is executed when an error occurs.
app.listen(app.config.listenPort, (err) => {
if (err) throw err
app.logger.info(`> Ready on http://localhost:${app.config.listenPort}`)})Copy the code
Route error Handling
It may also have different error handling logic for each route, so incoming requests may need to return different exception codes and information depending on the situation.
router.get('/loginAuth'.async (ctx, next) => {
try {
const code = query.code
const res = await requestToken(code)
if(res.data.code ! = =0) {
ctx.app.logger.error(`request token error.Code is ${res.data.code} || response is: The ${JSON.stringify(res.data.data)} || msg: ${res.data.message}`)
ctx.body = {
code: 10000.message: `request token by code error`}}else {
ctx.body = res.data
}
} catch (err) {
ctx.app.logger.error(`request api has exception ${ctx.request.url} || ${err.code} || ${err.message} || ${err.stack}`)
ctx.body = {
code: 500.message: `Error response`}}})Copy the code
5. To summarize
- Usually the exception may be expected or exceed the expected, however, using
try/catch
No problem. - Use as much as possible for unexpected errors
catch
To make sure they’re captured. - Add the error handler to
window
Object, it will catch an asynchronous errorDRY
andSOLID
The principle. A global error handler can help you keep asynchronous code clean.
Reference
async-await-error-handling
nodejs-v12-lts