在express
中时应用 Async/await
编写异步代码时,每个 async 函数都要包裹在try/catch
中,代码量多了看着冗余不优雅,express
又不像koa
的异步机制能够订阅全局的error
事件,为了解决这个问题,须要写个捕捉异步函数异样的中间件。
uncaughtException
开始能想到的必定是try/catch
了,然而也想过是否应用nodejs
提供的uncaughtException
事件,在全局捕捉异样,例如上面的代码:
process.on("uncaughtException", (err) => console.log("uncaught Exception"));const asyncError=()=>{ throw new Error("some Error");}asyncError();
asyncError
办法外面抛出的异样会被 uncaughtException
订阅,然而在异步函数中,并没走到 uncaughtException
,还是会抛出异样:
process.on("uncaughtException", (err) => console.log("uncaught Exception"));const asyncError=()=>{ throw new Error("some Error");}(async ()=>{ // 抛出异样 asyncError();})()
而且Promise.reject
也没走到uncaughtException
外面:
const asyncError=()=>{ return Promise.reject("some error")}(async ()=>{ // 抛出异样 await asyncError();})()
所以在express
中应用nodejs提供的uncaughtException
解决异步谬误不太适合,一方面没法捕捉和定位上下文谬误,另一方面也没法将谬误异样提供给中间件函数解决
解决思路
要解决express
中的异步函数谬误,最好的办法当然是编写解决异样的中间件了,try/catch
开路,包裹中间件办法,catch
到的异样间接交给next
函数解决,代码如下:
const asyncHandler = fn =>{ return (req,res,next)=>{ try{ fn(req,res,next) }catch(next) }}module.exports = asyncHandler;
接下来,在异步函数中引入中间件解决:
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);}));
应用asyncHandler
办法包裹的async/await
函数,如果呈现谬误就会被Error-handling
中间件捕捉了
然而每次用到异步函数的时候都要包裹asyncHandler
办法,真正用起来也不是很爽,这里举荐应用express-async-errors中间件,其原理是将express
外面的两头全副包裹上一层asyncHandler
办法,让谬误异样无所遁形,全副跑到Error-handling
中间件。
前提是引入express
后,先引入express-async-errors
办法:
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);});
接下来的在异步函数中,就不必都包裹上try/catch
了,有谬误提前throw Error
,写起代码来美滋滋:
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);});~~~~
参考链接:
Using Async/await in Express
Handling errors in express async middleware