Bootstrap

async/await 如何优美的处理异常?

本着一种学习的态度写了此话题,如有不妥之处还请各位大牛多多指点.

Purpose: 此解决方案,可以避免业务代码中出现大量的try/catch, 众所周知try/catch对性能方面有一定的影响,另一方面try/catch在Node.js >= v8.3.0以后对性能的损耗是可以忽略不计的.

try/catch具体文献: However for Node 8.3+ the performance hit of calling a function inside a try block is negligible.

1. try/catch方法处理异常
async updateArticleById(ctx, next){
		 let id = ctx.params["id"];
       let body = ctx.request.body;
       try {
           let ret = await Services.admin.updateArticle(id, body);
           ctx.body = {ret: 0, data: ret};
       } catch(e) {
           ctx.body = {ret: 1, data: null, err: e.message || e.stack};
       }
}
  • 以上捕获异常是使用try/catch的方式来处理,因为await后面跟着的是Promise对象,当有异常的情况下会被Promise对象的内部
  • catch捕获,而await就是一个then的语法糖,并不会捕获异常, 那就需要使用try/catch来捕获异常,并进行相应的逻辑处理。
2. 封装异常处理函数
  • 知道了上面异常会被Promise对象自身的catch捕获异常,可以使用下面的解决方案 to.js
module.exports = (promise) => {
   if(!promise || !Promise.prototype.isPrototypeOf(promise)){
       return new Promise((resolve, reject)=>{
           reject(new Error("requires promises as the param"));
       }).catch((err)=>{
           return [err, null];
       });
   }
   return promise.then(function(){
       return [null, ...arguments];
   }).catch(err => {
       return [err, null];
   });
};

格式[error, …result]

  • 采用类似Golang风格的错误返回方式, 这里指定第一个参数为错误参数,后面为正常返回结果
  • if块是用来处理非法参数,并返回错误[err, null]
  • await后面如果是一个promise对象,那么await的任务就是在等待promise.resolve,而to.js就是主动去调用then和catch,主动处理并重新封装结果,并且在then或是catch里面继续返回封装后的数据,返回值对于await来说仍然是一个promise对象,然而resolve的值却是一个可迭代的对象[error, …result]

这个可迭代的对象如何使用 ?

async updateArticleById(ctx, next){
       let body = ctx.request.body;
       let id = ctx.request.params["id"];
       let [err, ret] = await ctx.app.utils.to(Services.admin.updateArticleById(id, body));
       if(err) {
           return ctx.body = {ret: 1, data: null, err: err};
       }

       ctx.body = {ret: 0, data: ret};
   }
;