前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Thinking--异步请求函数return应不应该加await?

Thinking--异步请求函数return应不应该加await?

作者头像
奋飛
发布2021-08-31 17:02:13
4970
发布2021-08-31 17:02:13
举报
文章被收录于专栏:Super 前端Super 前端

Thinking系列,旨在利用10分钟的时间传达一种可落地的编程思想或解决方案。

在 codereview 代码中,发现了这样的两种写法。

写法一:

代码语言:javascript
复制
async function fn () {
  return await someAsyncReq()
}

写法二:

代码语言:javascript
复制
function fn () {
  return someAsyncReq()
}

有哪些区别呢?从写法上,直观可以看到的是

  • 写法一:返回的是执行结果(异步执行过程在 fn 函数内部)
  • 写法二:返回的是 Promise(异步执行过程在**调用 fn **函数的方法)

我们知道,调用 async 包裹的函数也需要通过 async...await 进行处理;同样的获取异步结果,也可以通过 async...await 处理,那么上述调用方式一直:

代码语言:javascript
复制
await fn()

从这个层面看,貌似我们可以忽略具体返回是 retrun promise 还是 return await promise 。这个结论,在一定场景下的确没有问题 – 异步函数没有异常抛出

代码语言:javascript
复制
/*写法一:示例*/
async function fn1 () {
   return await new Promise(reslove => setTimeout(() => reslove('ligang'), 1000))
}
/*写法二:示例*/
function fn2 () {
   return new Promise(reslove => setTimeout(() => reslove('ligang'), 1000))
}

await fn1()
await fn2()

上述执行结果一致,都会在 1000ms 后返回 “ligang”。


那么什么场景下,上述两种写法会有差异呢?

写法一:

代码语言:javascript
复制
async function fn () {
  try {
    return await someAsyncReq()
  } catch (err) {
    return await Promise.rejct('异步操作发生错误')
  }
}

写法二:

代码语言:javascript
复制
function fn () {
  try {
    return someAsyncReq()
  } catch (err) {
    return Promise.rejct('异步操作发生错误')
  }
}

当异步操作发生异常时,会有差异:

  • 写法一:会返回异常信息,即执行 catch 部分
  • 写法二:异常的捕获需要在调用的函数中处理,fn 函数中 catch 部分无法执行

如果仔细分析,相信大家可以得出相应的结论。

代码语言:javascript
复制
function promisedDivision(n1, n2) {
  if (n2 === 0) {
    return Promise.reject(new Error('Cannot divide by 0'))
  }
  return Promise.resolve(n1 / n2)
}


/*写法一:示例*/
async function fn1 () {
   try {
     return await promisedDivision(6, 0)
   } catch (err) {
     return err
   }
}
/*写法二:示例*/
function fn2 () {
   try {
     return promisedDivision(6, 0)
   } catch (err) {
     return err
   }
}

await fn1()	// Error: Cannot divide by 0
await fn2() // Uncaught Error: Cannot divide by 0

对于方式一,reject 的错误被成功捕获;对于方式二,reject 的错误被直接抛出了(Uncaught)。对于异常的处理,是提升代码鲁棒性的重要途径之一。且对错误未捕获,会导致程序终止执行。

结论

  • 如果当前场景,需要我们对错误统一处理,建议使用写法一 return await someAsyncReq()在函数内部统一处理
  • 如果当前场景,需要我们对错误差异化处理,建议使用写法二 return someAsyncReq()调用者可差异化处理
代码语言:javascript
复制
// return await promise
aysnc function _request(options) {
  try {
     return await axios(options)
  } catch (err) {
    let errorMsg = '请求发生了错误'
    if (err.code === 'ECONNABORTED') {
      errorMsg = '请求超时!'
    } else if (axios.isCancel(err)) {
      errorMsg = '请求被取消!'
    } else {
      switch (err.response.status) {
        case 401: // token失效
        case 403: // 无权限访问
        case 404: // 接口不存在
        case 500: // 接口错误
      }
    }
    return await Promse.reject({
      errorCode: err.response.status,
      message: `${errorMsg}:${err}`
    })
  }
}

// return promise
async function request (options) {
  return new Promise((resolve, reject) => {
    try {
      const {status, content} = _request(options)
      if (status === 'success'){
        resolve(content)
      } else {
        reject({
          errorCode: status,
          message: content
        })
      } 
    } catch (err) {
      reject(err)
    }
  })
}

项目中对 axios 请求经常会按照上述原则进行封装,axios 请求我们直接 return await promise 处理,便于对统一错误进行通用性处理(如401、403、500等),一致性强,减少不必要的冗余代码;而对于业务端我们采用 return promise 处理,如 status !== 'success' 情况,将错误抛出由调用者根据业务情况进行差异化处理,灵活度更高,更能契合业务需求。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2021-08-23 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 结论
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档