JS异步编程全解析:从Promise到Async Await实战应用
日期:2025-05-19 13:08:44 •原创
你写的网页是不是经常像老年手机一样卡成PPT?点个按钮转圈圈半天,最后弹个"网络异常"?别慌!今天就带你破解JS异步编程的"祖传难题",看完这篇包你代码丝滑得像德芙巧克力!
一、先搞懂这锅"粥"是怎么煮糊的
举个活生生的例子——电商购物车加载:
javascript复制// 老式回调写法(新手千万别学!) getCartItems(userId, (items) => { calculateTotal(items, (total) => { applyCoupons(total, (finalPrice) => { updateUI(finalPrice) // 到这里已经头晕了 }) }) })
这代码像不像煮糊的粥???三大致命伤??:
- 错误处理要每个回调都写一遍(累不累啊)
- 改需求等于重写(产品经理狂喜)
- 内存泄漏防不胜防(页面越用越卡)
二、Promise:给你的代码装个进度条
想象在餐厅排队取号的感觉,Promise就是这个电子叫号器:
javascript复制// 改造后的购物车流程 fetchCartItems(userId) .then(items => calculateTotal(items)) .then(total => applyCoupons(total)) .then(finalPrice => { updateUI(finalPrice) return sendToPayment(finalPrice) // 还能接着链式调用 }) .catch(error => { console.log('哪个环节翻车了:', error) })
??必记的五个知识点??:
.then()
里的返回值会自动包装成新PromisePromise.all()
适合并发多个请求(比如同时加载商品图和详情)Promise.race()
用来做超时控制(移动端必备)- 链式调用不是必须垂直对齐(别被代码格式绑架)
- 永远在最后加
.catch()
(保命符啊!)
常见翻车现场:
javascript复制// 错误示范! loadData().then(result => { setTimeout(() => { // 这里埋了个定时炸弹 return process(result) }, 1000) }) // 正确姿势要加return loadData().then(result => { return new Promise(resolve => { setTimeout(() => resolve(process(result)), 1000) }) })
三、Async/Await:把异步写成同步的"障眼法"
这玩意儿就像网购时查物流,虽然要等快递,但不用盯着手机看:
javascript复制async function checkoutFlow() { try { const items = await fetchCartItems() // 等购物车数据 const total = await calculateTotal(items) const finalPrice = await applyCoupons(total) // 并发优化技巧(同时请求支付和更新库存) const [paymentResult, stockUpdate] = await Promise.all([ initPayment(finalPrice), updateInventory(items) ]) return showSuccessPage(paymentResult) } catch (error) { // 统一错误处理 if(error instanceof PaymentError) { showError('银行卡余额不足') } else { showError('系统开小差了') } } }
??三大实战技巧??:
- 用
Promise.all()
打包多个await(提速神器) - 在循环里慎用await(改用
for...of
逐条处理) - 记得给异步函数起名字(调试时能看清调用栈)
特殊场景处理:
javascript复制// 文件上传进度条 async function uploadFile(file) { const reader = new FileReader() // 传统事件监听转Promise const readPromise = new Promise(resolve => { reader.onload = resolve }) reader.readAsDataURL(file) await readPromise // 显示预览图 previewImage(reader.result) }
四、Promise和Async/Await的"爱恨情仇"
通过对比看门道:
场景 | Promise方案 | Async/Await方案 |
---|---|---|
错误处理 | .catch()统一处理 | try/catch块包裹 |
条件判断 | 需要嵌套then | 可以直接用if语句 |
中间值传递 | 需要层层传递 | 变量直接赋值 |
调试难度 | 断点难跟踪 | 跟同步代码一样 |
浏览器兼容性 | IE11+ | 需要Babel转译 |
五、自问自答时间
Q:学了Async还要用Promise吗?
A:必须的!就像会开车也得懂点修车,遇到Promise.all()
这种场景还是原生的香
Q:await会阻塞页面渲染吗?
A:完全不会!JS引擎的事件循环机制在背后默默工作,你尽管await,渲染交给浏览器
Q:怎么取消异步操作?
A:上AbortController
这个神器:
javascript复制const controller = new AbortController() // 发请求时带上signal fetch('/api/data', { signal: controller.signal }) // 需要取消时调用 controller.abort()
六、移动端专属优化技巧
- ??弱网处理??:给每个请求加超时
javascript复制function fetchWithTimeout(url, timeout=5000) { return Promise.race([ fetch(url), new Promise((_, reject) => setTimeout(() => reject(new Error('请求超时')), timeout) ) ]) }
- ??省电模式??:用
requestIdleCallback
处理非紧急任务 - ??内存优化??:及时清理未完成的Promise
小编说句掏心窝的
干了八年前端的老司机送你三句话:
- ??别瞧不起回调函数??(某些库必须用回调)
- ??Async/Await不是银弹??(复杂流程结合Promise更香)
- ??先写能跑的代码??(优化是后面的事)
最后提醒新手:看见await
后面跟个同步函数?赶紧删掉!这就像用跑车送外卖——不是不行,但真没必要!
本文由嘻道妙招独家原创,未经允许,严禁转载