在前端开发(特别是 Vue3 + uni-app)里,我们经常需要去调用接口拿数据。但接口是网络请求,它不是立即就能返回结果的,而是异步的。这时候,async 和 await 就是我们最常用的“神器”。

1. 为什么需要 async/await?

以前我们写异步代码,一般长这样:

uni.request({
  url: '/api/article/latest',
  success: (res) => {
    console.log('拿到数据', res)
  },
  fail: (err) => {
    console.error('网络错误', err)
  }
})

看上去没问题,但如果请求很多,就会变成“回调地狱”,代码层层嵌套,非常难看。

回调写法

uni.request({
  url: '/api/a',
  success: (resA) => {
    uni.request({
      url: '/api/b',
      success: (resB) => {
        console.log('先拿到A,再拿到B')
      }
    })
  }
})

而 async/await 的出现,就是让异步代码写起来像“同步”一样直观:

async function fetchData () {
  try {
    const res = await uni.request({ url: '/api/article/latest' })
    console.log('拿到数据', res)
  } catch (e) {
    console.error('网络错误', e)
  }
}

2. async 和 await 到底是什么?

  • async:用来声明一个函数是“异步函数”。

    • 作用:这个函数的返回值一定是一个 Promise。

  • await:只能在 async 函数里用,意思是“等这个 Promise 执行完再往下走”。

换句话说,await 会让代码“停一下”,直到结果回来。
但注意:它只是暂停当前函数,不会卡死整个页面。

3. 在 uni-app 里怎么用?

最常见的场景:请求后端接口。

async function fetchLatestNotices () {
  try {
    const res = await uni.request({
      url: '/api/article/latest',
      method: 'GET',
      data: { category: 3, limit: 2 }
    })

    // 1. HTTP 状态码
    if (res.statusCode !== 200) throw new Error('网络异常')

    // 2. 后端业务状态码(假设后端返回 { code, msg, data })
    if (res.data.code !== 200) throw new Error(res.data.msg || '接口出错')

    // 3. 取业务数据
    const list = res.data.data || []
    console.log('业务数据', list)

  } catch (err) {
    console.error('请求失败', err)
  }
}

这样写逻辑特别清晰:

  1. 先判断 HTTP 层面有没有成功

  2. 再判断后端的业务返回是否成功

  3. 最后取出真正的数据

res的解析

1. 网络层(uni.request 的原始返回)

const res = await uni.request({ url: '/api/article/latest' })

这时 res 的结构大致是:

{
  data: {...},      // ← 后端返回的整个响应体
  statusCode: 200,  // HTTP 状态码
  header: {...},    
  errMsg: "request:ok"
}

statusCode 是 HTTP 状态码,由网络层返回。

2. 后端 Ajax 返回的结构

常见的后端接口会返回类似

{
  "code": 200,
  "msg": "操作成功",
  "data": [
    { "id": 1, "title": "通知1" },
    { "id": 2, "title": "通知2" }
  ]
}

这时:

  • res.data 就是上面整个 JSON 对象。

  • res.data.data 才是业务真正的数据数组。

4. 生命周期里调用

在 Vue3 + uni-app 里,通常在生命周期调用:

import { onMounted, onShow } from '@dcloudio/uni-app'

onMounted(() => {
  fetchLatestNotices()   // 页面第一次加载时执行
})

onShow(() => {
  fetchLatestNotices()   // 每次切回页面时再刷新
})

5. 最佳实践:封装请求方法

为了避免每个地方都写一堆重复的判断,我们可以封装一个 request 工具函数:

// utils/request.js
export async function request (options) {
  const res = await uni.request(options)
  if (res.statusCode !== 200) throw new Error('网络错误')
  if (res.data.code !== 200) throw new Error(res.data.msg || '接口错误')
  return res.data.data
}

以后用的时候,只要写:

import { request } from '@/utils/request.js'

async function fetchNotices () {
  try {
    const list = await request({ url: '/api/article/latest', method: 'GET' })
    console.log('拿到数据', list)
  } catch (e) {
    uni.showToast({ title: e.message, icon: 'none' })
  }
}

6. 总结

  1. async 标记异步函数,await 等待 Promise。

  2. await 让异步逻辑看起来像同步执行,代码更清晰。

  3. 在 uni-app 里,常见用法就是配合 uni.request 来写接口调用。

  4. 建议统一封装请求函数,避免重复写“HTTP 状态码 + 业务状态码”的判断逻辑。

一句话记住:没有 async/await,你写异步就像走迷宫;有了它,代码就像一条直路。

async/await 只是“语法糖”,并不会加快影响速度,真正影响速度的,是你选择“顺序请求”还是“并发请求”

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐