用 Fetch 加 async/await 把异步写的舒服

举报
茉莉风铃 发表于 2026/09/05 08:50:55 2026/09/05
【摘要】 用 Fetch + async/await 替代回调调接口:await fetch 拿响应、await res.json 取数,POST 设 method/headers/body 并用 res.ok 判成败,try/catch 兜底,无依赖请求用 Promise.all 并发,附超时 AbortController、凭证、并发控制等注意点。

过去那时候调接口都是 XMLHttpRequest 配回调函数,多个请求有依赖就一层套一层,变成"回调地狱",缩进越来越深、错误处理还散,代码一多钱起来就看的头皮发麻。后来有了 Promise,再后来有了 async/await好了很多了,异步代码能写成看起来像同步的样子,读起来顺、改起来也方便。浏览器自带的 Fetch 返回的就是 Promise,配合 async/await 是现在前端调接口的标准写法。

一、回调到 async/await 的变化

回调时代大概是:

fetch("/api/user").then((r) => r.json()).then((data) => {
  console.log(data)
})

用 then 链比嵌套回调好些,但逻辑一多还是一串。换成 async/await:

async function getUser() {
  const res = await fetch("/api/user")
  const data = await res.json()
  return data
}

await 会"等"这个 Promise 完成再往下走,代码从上往下读,没有缩进地狱。async 函数本身返回 Promise,调用方还能继续 .then 或再 await。

二、请求带参数和请求体

GET 带查询参数拼到 URL 上;POST 用 method + body(默认 Fetch 不带头、不自动带 cookie,要显式设):

async function createUser(payload) {
  const res = await fetch("/api/user", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(payload),
  })
  if (!res.ok) throw new Error("创建失败 " + res.status)
  return res.json()
}

几个点:Fetch 默认不发送 Cookie,跨凭证请求要加 credentials: ‘include’;Content-Type 要自己设,否则后端可能按表单解析;res.ok 是状态码 200-299 为 true,非 2xx 不会抛异常,得自己判断并 throw,否则错误被当成功吞掉。

三、错误处理

async 函数里用 try/catch 接住网络错误和主动抛的错:

async function safeGet() {
  try {
    const data = await getUser()
    render(data)
  } catch (e) {
    showError("加载失败:" + e.message)
  }
}

网络断开、超时、后端 500,都会进 catch。把错误展示出来比静默失败好,用户至少知道出了事。

四、多个请求并发:Promise.all

两个接口没依赖,别串行等,用 Promise.all 一起发:

const [user, orders] = await Promise.all([
  fetch("/api/user").then((r) => r.json()),
  fetch("/api/orders").then((r) => r.json()),
])

Promise.all 等全部完成,结果按顺序放回数组;其中一个 reject 整个就 reject。要"各自失败不影响彼此"用 Promise.allSettled。注意 Promise.all 不限制并发数,成百个请求一起发会被浏览器或后端限流,那种场景要自己分批或加并发控制。

五、几个要注意的点

第一,Fetch 的超时得自己写,它原生不支持 timeout,常用 AbortController 取消请求实现超时。第二,默认不带 Cookie,跨域带凭证要 credentials:‘include’ 且服务端允许。第三,res.json() 只能调一次,调完流就消费了,要多次读得先 clone。第四,大文件上传用 FormData 而不是手写 JSON,浏览器会自己设 multipart 边界。第五,await 只能写在 async 函数里,顶层要用就用 IIFE 或模块顶层的 top-level await(现代环境支持)。第六,别在循环里 await 一堆本可并行的请求,那是把并发硬生生写成串行,慢。

六、小结

前端调接口用 Fetch + async/await 最顺:await fetch 拿响应、await res.json 取数据,代码从上往下读没有回调地狱。POST 设好 method/headers/body、用 res.ok 判断成败、try/catch 兜底错误、无依赖的请求用 Promise.all 并发。超时靠 AbortController、凭证靠 credentials。比老式回调清晰得多,也是现在的主流写法。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。