关于 promise 和 async/await 写法问题?

小夜勃
  • 221

有一个关于 async 的写法问题, 如下:

定义了一个 api, fetchUser(), 可以有两种写法:

第一种, 不进行错误的显示处理

const fetchUser = async () => {
  const res = await axios.get('https://example.com')
  return res.data
}

第二种, 使用try..catch包裹

const fetchUser = async () => {
  try {
    const res = await axios.get('https://example.com')
    return res.data
  } catch (e) {
    throw e.response
  }
}

使用上貌似没有差别, 如下:

fetchUser()
  .then(user => console.log(user))
  .catch(err => console.error(err))

个人的疑惑在于错误的捕获和处理, 个人理解在于, 只要是出现了错误, 那么返回的 promise 对象就变成 reject, 只是第二个使用了 catch 捕获后包裹了一下错误信息再手动抛出. 第一种少些了一点代码...

所以想请教一下:

  1. 这两种写法有没有具体的差别, 或者说, 再更加复杂的异步情况下会有哪些不同?
  2. 使用哪种写法更加优雅?

若能解答, 不胜感激, 多谢!

回复
阅读 1.9k
6 个回答
✓ 已被采纳

在你这个情景下对调用者来说2个函数没差,你捕获错误又原样抛出多此一举。

但在大规模应用下你最外层得套一层try catch来统一处理错误吧?这个时候第二种写法就很有用了,可以额外加error_messagethrow出去,让最外层迅速知道发生错误的是什么原因,问题出现在哪个函数,给出准确提示。你如果不做二次try catch封装想实现这种效果就难度大了。

你的问题不是不知道 async/await 与 Promise 的区别,是不知道怎么写 try...catch...

try...catch... 的目的是捕获错误,并进行处理。发生错误 意味着开发者不知道接下来怎么做,只能抛出错误,让其它开发者处理。捕获错误 意味你明白接下来的代码有一些风险,你也打算处理发生的错误。

具体到你的例子里,http request 可能面临网络断开、服务器出错、返回数据格式不对等错误,所以我们可以捕获这些错误,给出对应的提示。比如网络断开,就让用户联网;服务器出错,让用户等下再试试;格式不对,让用户反馈问题给某某。至于你怎么写,用 async/await 还是 promise,无所谓,没有什么区别。

但是你 catch 之后再抛出就莫名其妙了。

首先说你的个人疑惑和理解。

在大多数语言中,包括 JavaScript,没有 try catch 结构的函数就会直接抛出其过程中产生的异常。也就是说:

function a() {
  try {
    // ...do something
  } catch (e) {
    throw e
  }
}

function b () {
  // ...do something
}

这二者是等效的。而你的例子中,第二种方式里 catch 了 e 之后,throw 出去的不是 e 本身,而是 e.response,所以一二方式不等效。

更加复杂的异步情况下会有哪些不同,哪种更优雅

当你需要同时执行两个异步流程的时候,这两种写法就会有明显不同,并且 Promise 写起来更舒服。

使用 Promise 的写法如下:

task1().then(console.log)
task2().then(console.log) // 两个 take 并行执行

而由于配合 try catch 的 async/await 语法本身就旨在“用同步的方式编写异步流程”,所以这种场景明显不是他的强项:

// 这样写是不行的,因为 task2 要等到 task1 结束才会开始
// console.log(await task1())
// console.log(await task2())

const result1 = task1()
const result2 = task2()
console.log(await result1)
console.log(await result2) // 这样写虽然可以同时开始了,但写起来读起来都并不舒服

而当你有两个异步流程要执行,且其中一个依赖于另一个的结果时,async/await 就更优雅。

// Promise
task1().then((result1) => {
  task2(result1).then((result2) => {
    // 可以想像,如果有更多的步骤,会很头痛
  })
})

// async/await
const result1 = await task1()
const result2 = await task2(result1) // 舒服了

希望对你有帮助。

第二种情况抛出的错误对象 是 第一种情况error对象的response属性。别的没有什么区别

async/await就是为了解决Promise写法不易理解,逻辑分离的缺点。功能上没什么不同,async/await更优雅,写出的代码更容易理解。

DedSec?
  • 2
新手上路,请多包涵

await axios.get('https://example.com').catch(err => console.error(err)) 可以这样写不用 try catch

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
宣传栏