之前两篇 Promise 错误处理其实已经描述了大部分场景下的错误捕获问题。
结合 async/await 可以获得很好的开发体验。
express 也可以使用 async/await 来提升开发体验,但必须 try/catch 所有 await 才行。
那么今天的课题就是如何优雅的在 express 中使用 async/await 来提升开发体验。
Promise 错误
koa2 中,我们可以很容易的全局处理掉,因为他天生支持。
而 express 中则不是,全局的错误处理并不能捕获 Promise 错误。
1 | router.get('/', async (req, res) => { |
如果 db.userInfo()
报错了,express 无法捕获到这个错误,会报一个 UnhandledPromiseRejectionWarning
全局错误。
我们不得不加上 try/catch 来捕获异常。
1 | router.get('/', async (req, res, next) => { |
然后我们的路由中大量的 try/catch,不仅难看,写着也烦。
所以我们需要改善这块代码,提升开发体验。
捕获函数
1 | const asyncHandler = fn => (req, res, next) => |
可以看到,只要简单的几行代码,就可以处理掉错误问题了。
他会将错误捕获并交给 next
错误,这时候就会去到 express 全局错误中间件中。
但其实每个路由都加一个 asyncHandler
也不是特别优雅,或者不经意间忘记加了。
修改 express 路由层
1 | const Layer = require('express/lib/router/layer'); |
我们直接修改了路由层,只是把刚刚的 asyncHandler
代码放到了路由层中。
这样全局劫持了所有路由绑定,我们就可以非常正常的写我们的路由了。
这个只是个核心思想,推荐用完善的 express-async-errors 模块。
1 | router.get('/', async (req, res) => { |
这才是我们想要的样子。
如果你觉得侵入式的修改 express 方法不是特别安全,那就使用上面的方法吧,至少那是绝对安全的。
小结
这里介绍了两种方法帮助我们在 express 中优雅的捕获错误,大幅度的提升了开发体验。
其实,我原先自己实现的方案中代码略微啰嗦,后来参考了国外大佬的文章,才显的这么优雅。
甚至方案二,我的实现是劫持 app 实例,代码非常的不优雅。
参考:
Using async/await in ExpressJS middlewares
ES6 generators support for ExpressJS