ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

vue3-异步编程

vue3-异步编程 太棒了异步编程尤其是 Promise确实是前端开发中最核心也最容易出bug的知识点。别担心我们完全可以把这块硬骨头啃下来。既然你已经在写axios.get().then(res res.data)我们就从这段代码出发层层剥开Promise 的本质。一、为什么要异步先解决“为什么”JavaScript 是单线程的语言一次只能干一件事。如果所有代码都“排队”执行同步遇到网络请求或定时器时页面就会卡死阻塞直到请求结束。一个绝佳的比喻同步阻塞你去食堂打饭站在窗口前等着阿姨给你盛完你再端着走。期间你什么都干不了。异步非阻塞你去奶茶店点单店员给你一张小票Promise说“做好了叫号”。你拿着小票可以先去旁边逛逛街执行其他代码等听到叫号请求完成再回来取奶茶执行回调。二、Promise 到底是什么解决“是什么”Promise 就是一个“小票”或“契约”它代表一个尚未完成但将来会完成的操作。它有三个“一生”的状态Pending待定/进行中刚发起请求后端还没回消息。奶茶正在做Fulfilled已成功请求成功数据拿回来了。奶茶做好了叫号Rejected已失败请求失败网络断了或报错了。机器坏了做不了最核心的规则状态一旦从 Pending 变成 Fulfilled 或 Rejected就凝固了不能再变。三、拆解你的代码.then()做了什么export const getUserList (): PromiseUser[] { return apiClient.get(/users).then(res res.data); };这行代码的执行流程是这样的apiClient.get(/users)立即返回一个Promise对象状态为 Pending。.then(res res.data).then()是 Promise 的原生方法意为“等状态变成 Fulfilled成功后执行这个函数”。当后端返回数据时Promise 状态变为 Fulfilledres就是后端传回来的整个响应对象包含状态码、请求头、数据等然后我们箭头函数执行把res.data纯净的数据取出来。返回值.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 (): PromiseUser[] { 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.all和Promise.allSettled前端页面经常需要同时请求多个接口比如首页要同时拿用户信息和公告。如果你写await A(); await B();那是串行总耗时 A耗时 B耗时。正确的“同时发起”做法Promise.all全部成功才算成功适用场景三个接口数据必须全部拿到才能渲染页面。const [users, posts, messages] await Promise.all([ getUserList(), // 请求1 getPostList(), // 请求2 getMessageList() // 请求3 ]); // 三个请求同时发出总耗时 ≈ 最慢的那个请求时间 // 如果其中任何一个失败整个 Promise.all 会立即失败进入 catchPromise.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([...])并发请求各自返回结果各自安好分别下单谁成功拿谁第八、给你的实战建议避坑指南永远别忘记catch或try-catch不捕获错误前端页面可能会白屏尤其是在 Vue/React 中。async函数返回值一定是 Promise即使你写return 123外面拿到的也是Promise.resolve(123)。在循环中不要乱用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手动封装一个函数比如延迟等待随时告诉我我们继续深挖
返回列表