代码不会按预期运行,可能会出现意想不到的情况。为了保证程序的健壮性,需要进行异常处理。比如一个对象的所有方法都应该处理异常,但是如果每个方法都加一个trycatch就太麻烦了:constobj={aaa(){try{//aaa}catch(e){//xxxx}},bbb(){try{//bbb}catch(e){//xxxx}},ccc(){try{//ccc}catch(e){//xxxx}}}有办法吗不重复这么多次就对所有方法做异常处理?是的,就是代理模式。代理模式是通过包装目标对象,提供一个与目标对象同名的方法。最终的功能实现是调用目标对象的方法,但是可以增加一些额外的职责,比如日志,权限等,可以对目标对象透明。做一些增强。比如React中的高层组件就是代理模式的实现,可以透明的扩展封装组件的功能。显然,这里的异常处理也可以通过proxy来完成。但是你不必自己去实现,ES6提供了Proxy,可以基于它来实现。定义createProxy方法实现代理,创建一个Proxy对象,对target对象target做一层包装,定义get和set的处理:functioncreateProxy(target){constproxy=createExceptionProxy();returnnewProxy(target,{get:proxy,set:proxy});}functioncreateExceptionProxy(){return(target,prop)=>{if(!(propintarget)){返回;}if(typeoftarget[prop]==='function'){returncreateExceptionZone(target,prop);}返回目标[prop];}}如果target不包含prop,则返回空,否则返回对应的属性值target[prop]。如果属性值是函数,做一层包装:functioncreateExceptionZone(target,prop){return(...args)=>{letresult;ExceptionsZone.run(()=>{result=target[prop](...args);});返回结果;};}最后的函数实现是调用target,传入参数,将调用结果作为代理方法的结果返回。包裹这一层的目的是做异常处理,这就是ExceptionsZone.run所做的:静态运行(回调){尝试{回调();}catch(e){this.exceptionHandler.handle(e);}}}调用目标方法并尝试捕获。当异常发生时,使用ExceptionHandler来处理。这里的异常处理,我们简单的打印日志:}}这样,目标对象的所有方法都实现了添加异常处理的目的。测试中:constobj={name:'guang',say(){console.log('嗨,我'+this.name);},coding(){//xxxthrownewError('bug');}coding2(){//xxxthrownewError('bug2');}}constproxy=createProxy(obj);proxy.say();proxy.coding();这里的coding和coding2方法都会抛出异常,但是没有做异常处理。我们使用了代理来添加:通过代理方式,我们成功地为对象方法添加了异常处理!但是现在还是有问题。例如,如果我将编码方式更改为async不行:那我该怎么办?我们可以充当异步和同步方法的代理吗?实在是没有办法,因为没有办法区分方法是同步的还是异步的,两种方法的调用方式也不一样,但是我们可以分别提供一个runner方法来运行这些异步逻辑:classExceptionsZone{staticexceptionHandler=newExceptionHandler();staticasyncasyncRun(callback){try{awaitcallback();}catch(e){this.exceptionHandler.handle(e);然后像这样运行:(asyncfunction(){awaitExceptionsZone.asyncRun(proxy.coding2);})();这会在异步逻辑中处理异常:我们通过proxy添加对象的所有同步方法,它提供异常处理,然后提供运行异步方法的runner函数,处理运行时异常。结合这两种方法,将异常处理优雅地添加到目标对象的所有方法中。也许你会说代理就是代理,为什么要定义那么多类呢?因为我把这个逻辑从Nest.js的源码中抽取出来,就是在源码中如何给对象添加异常处理:异步逻辑也是单独提供方法运行的:我觉得这个透明添加异常处理的方法toobjects非常优雅,所以我从Nest.js源代码中提取它。总结为了保证健壮性,我们需要对所有可能报错的代码都添加异常处理,但是每个方法都添加trycatch太麻烦了,所以我们使用Proxy来实现代理,透明的给所有方法添加异常处理的对象。但是agent增加的只是同步异常处理,并没有捕获异步逻辑的异常。我们可以一个一个运行异步方法。结合proxy+提供运行异步方法的runner这两种方法,可以给一个不做任何异常处理的对象添加异常处理。是不是很优雅?
