news 2026/8/24 22:03:37

vue3-异步编程

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
vue3-异步编程

太棒了!异步编程(尤其是 Promise)确实是前端开发中最核心也最容易出bug的知识点。别担心,我们完全可以把这块硬骨头啃下来。

既然你已经在写axios.get().then(res => res.data),我们就从这段代码出发,层层剥开Promise 的本质。


一、为什么要异步?(先解决“为什么”)

JavaScript 是单线程的语言(一次只能干一件事)。如果所有代码都“排队”执行(同步),遇到网络请求或定时器时,页面就会卡死(阻塞),直到请求结束。

一个绝佳的比喻:

  • 同步(阻塞):你去食堂打饭,站在窗口前等着阿姨给你盛完,你再端着走。期间你什么都干不了。
  • 异步(非阻塞):你去奶茶店点单,店员给你一张小票(Promise),说“做好了叫号”。你拿着小票,可以先去旁边逛逛街(执行其他代码),等听到叫号(请求完成),再回来取奶茶(执行回调)。

二、Promise 到底是什么?(解决“是什么”)

Promise 就是一个“小票”(或“契约”),它代表一个尚未完成但将来会完成的操作。它有三个“一生”的状态:

  1. Pending(待定/进行中):刚发起请求,后端还没回消息。(奶茶正在做)
  2. Fulfilled(已成功):请求成功,数据拿回来了。(奶茶做好了,叫号)
  3. Rejected(已失败):请求失败,网络断了或报错了。(机器坏了,做不了)

最核心的规则:状态一旦从 Pending 变成 Fulfilled 或 Rejected,就凝固了,不能再变。


三、拆解你的代码:.then()做了什么?

export const getUserList = (): Promise<User[]> => { return apiClient.get('/users').then(res => res.data); };

这行代码的执行流程是这样的:

  1. apiClient.get('/users'):立即返回一个Promise对象(状态为 Pending)。
  2. .then(res => res.data)
    • .then()是 Promise 的原生方法,意为“等状态变成 Fulfilled(成功)后,执行这个函数”。
    • 当后端返回数据时,Promise 状态变为 Fulfilled,res就是后端传回来的整个响应对象(包含状态码、请求头、数据等),然后我们箭头函数执行,把res.data(纯净的数据)取出来。
  3. 返回值.then()本身也会返回一个新的 Promise,所以外部调用时还能继续.then()

灵魂拷问:如果不写.then(res => res.data),调用方拿到的就是整个响应对象,需要写response.data才能拿到数据。你现在的写法相当于提前把数据剥出来了,非常优雅。


四、处理错误:.catch().finally()

现实世界请求一定会失败(后端报错、断网)。只写.then()会“静默失败”,页面卡死没反应。

完整的 Promise 链写法:

apiClient.get('/users') .then(res => { console.log('成功', res.data); return res.data; }) .catch(error => { // 🔥 只要请求失败,或者 .then 里抛出了异常,都会进这里 console.error('请求出错了!', error.message); // 可以给用户弹个 Toast 提示 return []; // 返回一个空数组,防止外面报错 }) .finally(() => { // 无论成功还是失败,最后都会执行(类似 Java 的 try-catch-finally) console.log('请求结束,关闭 Loading 动画'); });

五、终极进阶:async/await(现代写法的“语法糖”)

上面的.then().catch()链式调用,一旦逻辑复杂起来会形成“回调地狱”(一大堆缩进)。ES7 推出了async/await,让异步代码长得像同步代码,极大提升可读性。

async/await重写你的getUserList

// 函数前面加 async export const getUserList = async (): Promise<User[]> => { try { // await 会“卡住”这一行,但只是假装卡住(实际上 JS 引擎去干别的活了), // 直到请求完成拿到结果,再赋值给 res const res = await apiClient.get('/users'); return res.data; // 这里的 return 相当于 Promise 的 resolve } catch (error) { // 相当于 .catch() console.error('请求失败', error); return []; // 异常时兜底 } finally { // 相当于 .finally() console.log('请求结束'); } };

调用时:

// 因为 async 函数返回的一定是 Promise,所以调用时要么 await,要么 .then() const fetchData = async () => { const users = await getUserList(); // 成功拿到 User[] console.log(users[0].name); };

六、高阶神器:并发请求(Promise.allPromise.allSettled

前端页面经常需要同时请求多个接口(比如首页要同时拿用户信息和公告)。如果你写await A(); await B();,那是串行,总耗时 = A耗时 + B耗时。

正确的“同时发起”做法:

  1. Promise.all(全部成功才算成功)
    适用场景:三个接口数据必须全部拿到才能渲染页面。

    const [users, posts, messages] = await Promise.all([ getUserList(), // 请求1 getPostList(), // 请求2 getMessageList() // 请求3 ]); // 三个请求同时发出,总耗时 ≈ 最慢的那个请求时间 // 如果其中任何一个失败,整个 Promise.all 会立即失败进入 catch
  2. Promise.allSettled(各自安好,互不影响)
    适用场景:某个接口挂了不影响其他数据显示。

    const results = await Promise.allSettled([ getUserList(), getPostList() ]); // results 是一个数组,每个元素都有 status: 'fulfilled' 或 'rejected' // 你可以手动过滤掉失败的,只渲染成功的

七、一张图总结(建议收藏)

方法作用类比
new Promise((resolve, reject)=>{})手动创建 Promise,调用resolve表示成功,reject表示失败自己去奶茶店下订单
.then(res => {})监听成功状态,拿到结果奶茶叫号,你去取
.catch(err => {})监听失败状态,捕获错误奶茶做砸了,店员给你退款道歉
.finally(() => {})无论成败,最后都执行无论喝没喝到,你都走出奶茶店
async/await用同步风格写异步代码像点菜一样写代码,但底层没阻塞
Promise.all([...])并发请求,全部成功才成功(一荣俱荣)团购,一个人不付款订单就取消
Promise.allSettled([...])并发请求,各自返回结果(各自安好)分别下单,谁成功拿谁

第八、给你的实战建议(避坑指南)

  1. 永远别忘记catch(或try-catch:不捕获错误,前端页面可能会白屏(尤其是在 Vue/React 中)。
  2. async函数返回值一定是 Promise:即使你写return 123,外面拿到的也是Promise.resolve(123)
  3. 在循环中不要乱用await:如果你在for循环里await发请求,那是一个一个发的(慢)。如果需要同时发多个,用Promise.all配合.map
// ❌ 错误:串行,耗时 3秒(假如每个1秒) for (let id of [1,2,3]) { await getUserById(id); } // ✅ 正确:并行,耗时 1秒 const promises = [1,2,3].map(id => getUserById(id)); await Promise.all(promises);

异步编程刚接触时确实有点绕,但核心就是“将来完成 + 不阻塞”。把Promise想象成外卖订单号,把await想象成“坐在家里等外卖(但不影响你刷手机)”,就很好理解了。

如果你想把async/await结合你的 Vue 组件(比如onMounted里调用)实战练一下,或者想看看new Promise手动封装一个函数(比如延迟等待),随时告诉我,我们继续深挖!😊

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/24 21:59:34

OpenArm:一副6500美元的7自由度开源协作机械臂是怎么做到的

OpenArm&#xff1a;一副6500美元的7自由度开源协作机械臂是怎么做到的 【免费下载链接】openarm A fully open-source humanoid arm for physical AI research and deployment in contact-rich environments. 项目地址: https://gitcode.com/GitHub_Trending/op/openarm …

作者头像 李华
网站建设 2026/8/24 21:59:19

DBeaver 崩溃后 5 分钟找回 SQL 脚本:完整指南

DBeaver 崩溃后 5 分钟找回 SQL 脚本&#xff1a;完整指南 【免费下载链接】dbeaver Free universal database tool and SQL client 项目地址: https://gitcode.com/GitHub_Trending/db/dbeaver DBeaver 崩溃后&#xff0c;最怕的就是没保存的 SQL 脚本找不回来。这篇文…

作者头像 李华
网站建设 2026/8/24 21:53:54

「AI 应用 / AI Agent」行业日报 · 2026-08-23

「AI 应用 / AI Agent」行业日报 2026-08-23 &#x1f4ca; 市场信号 阿里巴巴发布2027财年Q1财报&#xff0c;营收2690亿元&#xff0c;同期宣布新一轮业务架构调整&#xff1a;电商合并、云芯片整合、千问分拆为独立子公司 [数据来源&#xff1a;36氪《9点1氪》&#xff1b;…

作者头像 李华
网站建设 2026/8/24 21:51:09

Linux命令合集

ls查看当前目录下文件的相关信息cd .跳转当前目录cd ..跳转到上级目录pwd查看当前目录的绝对路径whoami可以查看当前登录的用户名su root可以切换到管理员which查找外部命令路径whereis查找命令的二进制、源码、手册页type显示命令类型&#xff08;内置/外部/别名&#xff09;c…

作者头像 李华