问题描述Express结合async/await可以获得很好的开发体验。一般情况下,一开始使用Promise时会使用async/await来处理错误,使用Promise.catch()来处理错误。async/await流行之后,大家习惯用try/catch来处理错误。router.get('/users',async(req,res,next)=>{try{constusers=awaitUser.findAll();res.send(users);}catch(err){logger.error(err.message,err);res.send([]);}});这样做本身并没有错,只是代码中会出现大量重复的try/catch。是否可以全局捕获异常并统一处理?假设router.get('/users',async(req,res,next)=>{constusers=awaitUser.findAll();res.send(users);});如果User.findAll()报错,express的全局错误处理无法直接捕获Promise错误。将报告UnhandledPromiseRejectionWarning错误。我们先来看一下快速错误处理的机制。express中定义的错误处理中间件函数的定义方式与其他中间件函数相同,区别在于错误处理函数有四个参数而不是三个:(err,req,res,next):app.use(function(err,req,res,next){console.error(err.stack);res.status(500).send('Somethingbroke!');});所以exprees中的正常处理和错误处理路径是分开的,多了一个err参数。app.use((err,req,res,next)=>{})对应Layer.handle_errorapp.use((req,res,next)=>{})对应Layer.handle_request解决方案ifexpress可以去抓`Promise`对象全局错误,需要另一层封装来处理Promise对象。constasyncHandler=fn=>(req,res,next)=>Promise.resolve().then(()=>fn(req,res,next)).catch(next);router.get('/users',asyncHandler(async(req,res)=>{constusers=awaitUser.findAll();res.send(users);}));asyncHandler会通过catch()捕获Promise中的错误,交给next,所以会去express全局错误中间件。但是如果在每一个路由请求中都添加这个asyncHandler函数来捕获异常,那和在每一个路由请求中都添加try/catch并没有太大区别。而且代码看起来也很复杂。还有一种更简单的方法,使用express-async-errors。原则是:这是一个非常简约和非侵入性的hack。它没有修补expressRouter上的所有方法,而是将Layer#handle属性包装在一个地方,使所有其余的express内容完好无损。翻译:这是一个非常简约和非侵入性的黑客攻击。它不是在每个express路由方法中打补丁,而是通过重写express中的Layer#handle方法将每个路由函数的错误传递给next(err)。用法也很简单。在express之后引入require('express-async-errors'),可以在express错误处理中捕获错误。//errorhandleapp.use((err,req,res,next)=>{logger.error(err.message,err);if(req.xhr){returnres.json({state:false,msg:err.message});}next(err);});最后希望Express下个大版本改进的时候,直接在核心代码中处理这个问题就完美了。
