解决代码中重复的捕获 promise 错误的 try catch 语句

promise

promise 的出现,提供了优雅的异步解决方式,可是,多个连续继发 promise 写法依然繁琐。react

let promise = new Promise(function(resolve, reject){
  // ...
  if(/* 异步任务执行成功 */) {
    resolve(value)
  } else {
    reject(error)
  }
})

promise.then(v => {}).catch(e => {})
复制代码

async

es6 以后又新增了 async 函数来优化异步写法,语义化更明确,写法更优雅,可是错误捕获比较麻烦,通常都得使用 try catch 来捕获错误,具体优势参考阮老师博客 async 函数es6

function promiseFunc = function(){
  return new Promise(function(resolve, reject){
    // ...
    if(/* 异步任务执行成功 */) {
      resolve(value)
    } else {
      reject(error)
    }
  })
}

async func(){
  let res = await promiseFunc()
}

// 错误捕获
async func(){
  try{
    let res = await promiseFunc()
  }catch(err){
    alert(err)
  }
}

复制代码

错误捕获优化

以下是工做中 react + mobx 项目中 action 的代码后端

class Actions {
  @action
  async deleteModel(params) {
    try {
      await this.post(apis.API_DEPLOY_DELETE, params)
      this.getDeployList(this.store.searchParams)
    } catch (e) {
      message.error(e.message || '出错了!请稍后重试')
    }
  }

  @action
  async getDirChain(params) {
    try {
      let r = await this.post(apis.API_DEPLOY_DIR_CHAIN, params)
      runInAction(() => {
        this.store.dirChain = r
      })
    } catch (e) {
      message.error(e.message || '出错了!请稍后重试')
    }
  }

}
复制代码

如上代码,两个 action 都是向后端异步请求数据, 每一个 action 函数中都用了 try catch 函数,这样重复写了几十个 action 函数api

必须干掉 try catchpromise

错误捕获装饰器尝试

装饰器简洁方便,首先尝试, class 方法装饰器函数以下app

const tryCatch = msg => (target, name, descriptor) => {
  const original = descriptor.value
  if (typeof original === 'function') {
    descriptor.value = async function(...args) {
      try {
        const result = await original.apply(this, args)
        return result
      } catch (e) {
        message.error(e.message || msg || '出错了!请稍后重试')
      }
    }
  }
  return descriptor
}
复制代码

如上代码,封装 tryCatch 装饰器来对每一个 action 函数添加 try catch 错误捕获。异步

属性方法装饰器中async

  • target 指向 class 实例
  • name 是被装饰的方法名
  • descriptor 是方法的属性修饰符

咱们能够经过 descriptor.value 获取到被装饰的方法,在 try catch 中执行函数,捕获错误或者返回结果函数

为了灵活提示错误信息,装饰器参数 msg 用来传入自定义提示文本post

  • 用法(该用法是错误的)
@tryCatch // @tryCatch('运行出错')
@action
async getDirChain(params) {
  let r = await this.post(apis.API_DEPLOY_DIR_CHAIN, params)
  runInAction(() => {
    this.store.dirChain = r
  })
}
复制代码

以上对 async 函数进行错误捕获的用法是错误的

如上的写法是错误的,这种装饰器只能对同步代码产生做用,异步的是无效的,以前理解错误了

最后仍是解决了 try catch 问题

直接 async await 函数封装就好了,简单的问题想复杂了。。。

定义请求执行公共函数

/** * @param {string} method request method; ('get', 'post') * @param {string} api request url * @param {object} params payload * @memberof BaseActions */
request = async (method, api, params = {}) => {
  const requestFunc = async () => {
    let r = null
    try {
      r = await this[method](api, params)
    } catch (e) {
      message.error(e.message)
    }
    return r
  }

  return await requestFunc()
}
复制代码

原有包含 try catch 重复代码函数修改

@action
async getDirChain(params) {
  let r = await this.request('get', apis.API_DEPLOY_DIR_CHAIN, params)
  r && runInAction(() => this.store.dirChain = r)
}
复制代码

终于不用不停写重复代码了。。。