decorator/errSafe.js

/**
 * 修饰器,实现各种错误处理
 * @module errSafe
 */

/**
 * 捕获async函数中的异常,并进行错误提示
 * 函数正常结束时应 return 'ok',return其它文案时将toast指定文案,无返回值或产生异常时将toast默认文案
 * @param {string} defaultMsg  默认文案
 * @param {number} [duration] 可选,toast持续时长
 * 
 * @example
 * class Demo {
 *   //领取奖励
 *   \@withErrToast({defaultMsg: '服务异常'}) //领取过程出现异常时,自动捕获异常并toast提示“服务异常”,避免交互无响应
 *   async acquireReward(){
 *     //各种处理....
 *     // return acquireRes.errMsg; //使用接口返回的异常信息作为提示文案
 *     
 *     return 'ok'; //标示函数正常结束
 *   }
 * }
 */
export function withErrToast({defaultMsg, duration=2000}) {
  return function (target, funcName, descriptor) {
    let oriFunc = descriptor.value;
    descriptor.value = async function () {
      let errMsg = '';
      let res = '';
      try {
        res = await oriFunc.apply(this, arguments);
        if (res != 'ok')
          errMsg = typeof res === 'string' && !/^\s*$/.test(res) ? res : defaultMsg;
      } catch (e) {
        errMsg = defaultMsg;
        console.error('caught err with func:',funcName, e.message, e);//真机下不支持打印错误栈,导致e打印出来是个空对象;故先单独打印一次e.message
      }

      if (errMsg) {
        this.$toast({
          title: errMsg,
          type: 'fail',
          duration: duration,
        });
      }
      return res;
    }
  }
}

/**
 * 捕获函数异常,避免阻断主流程
 * 支持同步函数和async函数
 * @example
 * class Demo {
 *   //解析banner数据
 *   \@errSafe //若解析过程出现异常,予以捕获,避免局部数据异常导致整个页面白屏
 *   parseDataBanner(){
 *   
 *   }
 * }
 */
export function errSafe(target, funcName, descriptor) {
  let oriFunc = descriptor.value;
  descriptor.value = function () {
    try {
      let res = oriFunc.apply(this, arguments);

      if (res instanceof Promise) {
        res.catch((e)=>{
          console.error('[errSafe decorator] caught err with func:',funcName, e.message, e);
        });
      }

      return res;
    } catch (e) {
      console.error('[errSafe decorator] caught err with func:',funcName, e.message, e); //真机下不支持打印错误栈,导致e打印出来是个空对象;故先单独打印一次e.message
    }
  }
}