vue3-async

太好了!我们来轻松愉快地学懂 async/await,这是 JavaScript 处理异步操作最现代、最优雅的方式。

1. 先看问题:什么是异步?

想象一下你同时做两件事:

  • 同步(排队):排队买奶茶,队伍很长,你只能干等着
  • 异步(多任务):网上点奶茶,等待时你还能刷手机、工作

异步代码就是:不用等前一个任务完成,就能做下一个任务。

2. 传统方式的问题(回调地狱)

先看看不用 async/await 的代码:

复制代码
// 场景:你要做三件事:煮面、煎蛋、吃饭

// 传统回调方式(很乱!)
煮面(function() {
  煎蛋(function() {
    吃饭(function() {
      洗碗(function() {
        // 更多嵌套...
      })
    })
  })
})

// 这种写法叫"回调地狱"(Callback Hell)
// 代码向右"生长",很难阅读和维护

3. Promise 登场(先理解这个)

Promise 就像"提货券":

  • 制作中(pending):奶茶还没做好

  • 已完成(fulfilled):奶茶做好了,可以取了

  • 已失败(rejected):奶茶打翻了,做不了

    // 创建一个Promise(就像拿到一张提货券)
    const 煮面Promise = new Promise((resolve, reject) => {
    setTimeout(() => {
    console.log('🍜 面煮好了!')
    resolve('香喷喷的面条') // 成功时调用
    }, 2000)
    })

    // 使用.then()取货
    煮面Promise.then((面条) => {
    console.log('我拿到了:', 面条)
    }).catch((错误) => {
    console.log('出错了:', 错误)
    })

4. async/await 来了!(更简洁的方式)

async/await 让异步代码看起来像同步代码一样简单!

基本规则:

  1. async:声明一个函数是"异步的"

  2. await:在 async 函数里,等待一个 Promise 完成

    // 1. 用 async 声明异步函数
    async function 做饭() {
    // 2. 用 await 等待
    const 面条 = await 煮面()
    const 鸡蛋 = await 煎蛋()

    console.log(🎉 可以吃饭了:${面条} + ${鸡蛋})
    return '美味的一餐'
    }

    // 调用
    做饭().then(结果 => {
    console.log(结果)
    })

5. 实际例子对比

场景:获取用户信息 → 获取订单 → 显示结果

复制代码
// 传统 Promise 方式(.then链)
function 获取用户信息() {
  获取用户()
    .then(用户 => {
      return 获取订单(用户.id)
    })
    .then(订单 => {
      return 显示结果(订单)
    })
    .catch(错误 => {
      console.error('出错了', 错误)
    })
}

// async/await 方式(简洁明了!)
async function 获取用户信息() {
  try {
    const 用户 = await 获取用户()
    const 订单 = await 获取订单(用户.id)
    const 结果 = await 显示结果(订单)
    return 结果
  } catch (错误) {
    console.error('出错了', 错误)
  }
}

6. 错误处理(try...catch)

async/await 用普通的 try...catch 处理错误,很简单!

复制代码
async function 点外卖() {
  try {
    console.log('📱 打开外卖APP...')
    
    const 菜单 = await 获取菜单()      // 可能失败:没网络
    const 订单号 = await 下单(菜单[0])  // 可能失败:余额不足
    const 外卖 = await 等待送达(订单号)  // 可能失败:外卖小哥摔倒了
    
    console.log('🎉 外卖到了!', 外卖)
    return 外卖
    
  } catch (错误) {
    // 任何一步出错都会到这里
    console.log('❌ 点外卖失败:', 错误.message)
    
    if (错误.message.includes('网络')) {
      alert('检查一下Wi-Fi?')
    } else if (错误.message.includes('余额')) {
      alert('余额不足,请充值')
    } else {
      alert('未知错误,联系客服')
    }
  }
}

7. 并行执行(提高效率)

有时候不需要等一个完成再做下一个:

复制代码
// 错误的:这样会很慢(一个一个等)
async function 慢速做饭() {
  const 饭 = await 煮饭()  // 等20分钟
  const 汤 = await 煮汤()  // 等15分钟
  const 菜 = await 炒菜()  // 等10分钟
  // 总共:45分钟!
}

// 正确的:一起做(并行)
async function 快速做饭() {
  // 同时开始做三件事
  const 饭Promise = 煮饭()  // 开始煮饭,不等
  const 汤Promise = 煮汤()  // 开始煮汤,不等
  const 菜Promise = 炒菜()  // 开始炒菜,不等
  
  // 等所有都完成
  const [饭, 汤, 菜] = await Promise.all([
    饭Promise, 
    汤Promise, 
    菜Promise
  ])
  
  // 总共:20分钟(按最慢的算)
  console.log('🍚 开饭啦!')
}

8. 实战:结合 axios 的 async/await

复制代码
// 1. 用 async 声明函数
async function 获取用户数据() {
  try {
    // 2. 用 await 等待请求完成
    console.log('🔄 正在获取用户数据...')
    
    // await 会"暂停"在这里,直到请求完成
    const 响应 = await axios.get('/api/user/123')
    
    console.log('✅ 获取成功!')
    console.log('用户信息:', 响应.data)
    
    // 可以继续发请求(看起来像同步代码)
    const 订单 = await axios.get(`/api/orders?userId=${响应.data.id}`)
    console.log('用户订单:', 订单.data)
    
    return 订单.data
    
  } catch (错误) {
    console.log('❌ 获取失败:', 错误.message)
    
    // 错误处理也很简单
    if (错误.response?.status === 404) {
      alert('用户不存在!')
    }
  }
}

// 调用这个函数
async function 页面加载() {
  const 订单数据 = await 获取用户数据()
  console.log('页面数据:', 订单数据)
}

页面加载()

9. 简单记忆法

复制代码
// async 就像"魔法咒语",念了这个咒语:
async function 魔法函数() {
  // 就可以在函数里使用"时间停止魔法":
  
  // 普通代码:立即执行
  console.log('第一步')
  
  // await:时间停止,等这个完成
  const 结果 = await 异步操作()
  
  // 继续执行
  console.log('第二步:', 结果)
}

// 总结成口诀:
// async 放函数前
// await 放 Promise 前
// 错误用 try-catch
// 并行用 Promise.all

10. 练习:你来试试

把下面的回调代码改成 async/await:

复制代码
// 原代码(回调地狱)
function 做饭() {
  煮饭(function(饭) {
    炒菜(function(菜) {
      摆桌(function() {
        吃饭(饭, 菜)
      })
    })
  })
}

// 改成 async/await(我帮你开个头):
async function 做饭() {
  try {
    const 饭 = await 煮饭()
    // 你的代码...
  } catch(错误) {
    console.log('做饭失败:', 错误)
  }
}

11. 常见问题解答

Q:什么时候用 async/await?

A:只要处理异步操作(请求数据、定时器、读取文件等)

Q:一定要用 try...catch 吗?

A:建议用,否则出错时程序会崩溃

Q:可以在普通函数里用 await 吗?

A:不行!await 必须在 async 函数里

Q:async 函数返回什么?

A:总是返回 Promise,即使你 return 一个普通值

复制代码
async function 例子() {
  return 'hello'  // 自动包装成 Promise
}

例子().then(结果 => {
  console.log(结果)  // 'hello'
})

12. 实际应用场景

复制代码
<template>
  <div>
    <button @click="加载数据">加载用户</button>
    <div v-if="loading">加载中...</div>
    <div v-else>{{ userData }}</div>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import axios from 'axios'

const loading = ref(false)
const userData = ref(null)

// async/await 让代码很清晰
async function 加载数据() {
  try {
    loading.value = true
    
    // 看起来像同步的,很易读
    const 用户 = await axios.get('/api/user/1')
    const 订单 = await axios.get(`/api/orders/${用户.data.id}`)
    const 地址 = await axios.get(`/api/address/${用户.data.id}`)
    
    // 合并数据
    userData.value = {
      ...用户.data,
      订单: 订单.data,
      地址: 地址.data
    }
    
  } catch (错误) {
    console.error('加载失败', 错误)
    alert('加载失败,请重试')
  } finally {
    loading.value = false  // 无论成功失败,都要关闭loading
  }
}
</script>

现在你理解了吗?我们来个小测试:

复制代码
async function 测试() {
  console.log('1')
  
  await new Promise(resolve => {
    setTimeout(() => {
      console.log('2')
      resolve()
    }, 1000)
  })
  
  console.log('3')
}

测试()
console.log('4')

// 输出顺序是什么?为什么?

告诉我你的答案,然后我们继续深入学习!😊

1423

相关推荐
YXWik61 小时前
记录前端请求接口在浏览器请求响应的Preview和Response展示的一样的问题
前端
2501_928996221 小时前
GPT-4o换DeepSeek迁移成本多少?中科热备解析API聚合平台技术账本
前端·数据库·人工智能
东风破_1 小时前
从跨域到 WebSocket:前端跨域方案、SSE 与双向实时通信详解
前端·后端
原则猫1 小时前
TS 类型工具
前端
excel2 小时前
Nuxt + Twin CSS 中宽度超过屏幕时底部出现空白的原因与解决方案
前端·javascript
计算机魔术师3 小时前
美国司法部正式站队 OpenAI,AI 训练的版权账要这么算了
前端
IT_陈寒4 小时前
React Hooks闭包陷阱差点让我加班到凌晨
前端·人工智能·后端
风骏时光牛马4 小时前
疑难Bug根因定位与问题复盘分析
前端
创新技术阁4 小时前
FastapiAdmin 系统日志体系与核心配置参数详解
前端·后端·fastapi