Explanation of express Asynchronous Function Exception Trapping Example

  • 2021-09-24 21:27:34
  • OfStack

When Async/await is used to write asynchronous code in express, every async function should be wrapped in try/catch, which is redundant and inelegant. Unlike koa's asynchronous mechanism, express can subscribe to global error events. In order to solve this problem, it is necessary to write a middleware that captures asynchronous function exceptions.

uncaughtException

try/catch was definitely the first thing that came to mind, but I also wondered if I could catch exceptions globally using the uncaughtException event provided by nodejs, such as the following code:


process.on("uncaughtException", (err) => console.log("uncaught Exception"));

const asyncError=()=>{
 throw new Error("some Error");
}

asyncError();

The exception thrown in the asyncError method will be subscribed by uncaughtException, but in the asynchronous function, the exception will still be thrown without going to uncaughtException:


process.on("uncaughtException", (err) => console.log("uncaught Exception"));

const asyncError=()=>{
 throw new Error("some Error");
}

(async ()=>{
 //  Throw an exception 
 asyncError();
})()

And Promise. reject didn't go into uncaughtException:


const asyncError=()=>{
 return Promise.reject("some error")
}

(async ()=>{
 //  Throw an exception 
 await asyncError();
})()

So using uncaughtException provided by nodejs to handle asynchronous errors in express is not suitable. On the one hand, it can't catch and locate context errors, and on the other hand, it can't provide error exceptions to middleware functions for processing

Solutions

To deal with express asynchronous function errors, of course, the best method is to write exception processing middleware, try/catch open circuit, wrapping middleware method, catch to the exception directly to next function processing, the code is as follows:


 const asyncHandler = fn =>{
 return (req,res,next)=>{
  try{
   fn(req,res,next)
  }catch(next)
 }
}
module.exports = asyncHandler;

Next, introduce middleware processing into asynchronous functions:


app.use(asyncHandler(async(req, res, next) => {
 await authenticate(req);
 next();
}));

app.get('/async', asyncHandler(async(req, res) => {
 const result = await request('http://example.com');
 res.end(result);
}));

The async/await function wrapped with the asyncHandler method is caught by the Error-handling middleware if an error occurs

However, every time asynchronous functions are used, the asyncHandler method should be wrapped, which is not very cool to use. It is recommended to use express-async-errors middleware here. Its principle is to wrap all the middle parts of express with one layer of asyncHandler method, so that there is no hiding place for errors and exceptions, and all of them run to Error-handling middleware.

The premise is that after express is introduced, express-async-errors method is introduced first:


const express = require('express');
require('express-async-errors');
const User = require('./models/user');
const app = express();

app.get('/users', async (req, res) => {
 const users = await User.findAll();
 res.send(users);
});

Next, in asynchronous functions, you don't have to wrap try/catch. If there is an error, advance throw Error and write the code to be happy:


app.use(async (req, res) => {
 const user = await User.findByToken(req.get('authorization'));

 if (!user) throw Error("access denied");
});

app.use((err, req, res, next) => {
 if (err.message === 'access denied') {
 res.status(403);
 res.json({ error: err.message });
 }

 next(err);
});~~~~

Reference link:

Using Async/await in Express Handling errors in express async middleware

Related articles: