在以前的项目中我发现每一个控制器大约都是这样写的html
async function findId (id) { let res; try{ res = await document.findById(id); }catch(e){ return false; } }
固然这么写其实没有任何问题,甚至是一个很好的习惯,他保证了错误能够被正常的捕获,另外能够在catch里随便作处理,好比console,错误日志。一切都看起来那么完美java
那么假设如今有一个开发就是那么刚,写了几十个控制器,而后都没加try catch,义正词严的说,这么多重复代码真的不能抽象一下统一处理吗。
好吧且不说抽象统一处理的事,解决问题才是目的。
解决吧,他刚我也刚,每一个控制器加上不就是了。。。呵呵哒,边骂边加,我想半天也差很少了。
这样真的好吗,万一如今在catch这须要根据e作一些特殊处理呢或者增长一个功能呢?egg的话有一个统一的errorhandle能够配置。确实把整个错误处理能够完整的抽象出来。spring
这里的话要提一个java大大朋友告诉个人spring的解决手段,面向切面编程,具体概念网上解释不少,大约能够理解为,在全部控制器前,或者说控制器和服务之间,这样的话就能够实现不少公共逻辑的抽象。
面向切面编程适合作的事,这个spring的实践实在太多我就不赘述了,错误异常处理,日志,权限,这些在切面上的实践都是很好的。编程
其实中间件我认为也属于一个切面,这个切面是在请求上下文中的,可是这个切面没法覆盖全部的要求,特别当你须要控制的功能不是以请求为粒度控制的时候,或者说仅仅须要对服务层的服务添加功能的时候。app
这里就以开头的那段代码的简化为例。首先是一个包装函数,用来包装全部的控制器的方法框架
function controllerWrap(controllerFn, self) { return async function() { let that = self; try { await controllerFn.apply(that, arguments); } catch(e) { throw(e); } }; }
其实注意点也就两个,注意上下文,而后是保证controllerFn的arguments不要丢了,其实也就是ctx和next的
在把全部的控制器实例化后(通常在都会把控制器造成单例模式,以后只要遍历这些单例中的方法包裹控制器函数就能够了)。固然能够在wrap中注入更多统一处理函数,也能够经过函数名作一些判断,好比对全部名字中包含save的函数进行单独的日志处理。async
egg在实践上是不太一致,由于控制器并不是简单的实例化,若是须要对egg的控制器的进行包装则须要在loader中进行包装。
参考:https://eggjs.org/zh-cn/advan...
以后会尝试根据现有的业务沉淀出一套egg之上的框架。函数