1. 异步编程的本质与挑战
前端开发中最令人头疼的问题之一就是异步代码的编写。作为一名经历过无数次异步陷阱的老前端,我深刻理解那种"代码看似能跑,实则暗藏杀机"的痛苦。让我们从一个真实的案例开始:
去年双十一大促,我们的电商平台遭遇了一个诡异的问题——用户点击"立即购买"后,偶尔会跳转到空白页面。经过通宵排查,发现问题出在这样一段代码:
javascript复制// 错误示例:异步操作未正确处理
function handlePurchase() {
fetchUserInfo().then(user => {
if (!user.vip) return
applyCoupon() // 忘记return这个Promise
})
redirectToCheckout() // 不等优惠券申请完成就跳转
}
1.1 JavaScript的单线程本质
JavaScript是单线程语言,这意味着它一次只能执行一个任务。想象你是一名咖啡师,面前排着长队:
- 接受订单(同步任务)
- 制作咖啡(同步任务)
- 等咖啡机工作(异步任务,如setTimeout)
- 收钱(同步任务)
浏览器通过事件循环机制来模拟"多线程"效果:
mermaid复制graph TD
A[调用栈] -->|执行| B[同步代码]
B -->|遇到| C[Web APIs]
C -->|完成| D[任务队列]
D -->|事件循环| A
1.2 异步编程的演进历程
前端异步处理经历了三个阶段进化:
- 回调地狱时代(2014年前)
javascript复制getUser(id, function(user) {
getOrders(user.id, function(orders) {
getItems(orders[0].id, function(items) {
// 金字塔代码...
})
})
})
- Promise时代(ES6)
javascript复制getUser(id)
.then(user => getOrders(user.id))
.then(orders => getItems(orders[0].id))
.catch(err => console.error(err))
- Async/Await时代(ES2017+)
javascript复制async function loadData() {
try {
const user = await getUser(id)
const orders = await getOrders(user.id)
return await getItems(orders[0].id)
} catch (err) {
console.error(err)
}
}
2. Promise深度解析
2.1 Promise的三种状态
每个Promise对象都有明确的生命周期状态:
| 状态 | 描述 | 是否可逆 |
|---|---|---|
| pending | 初始状态 | 是 |
| fulfilled | 操作成功完成 | 否 |
| rejected | 操作失败或被拒绝 | 否 |
2.2 创建Promise的正确姿势
新手常犯的错误是忽略reject处理:
javascript复制// 错误示例
new Promise((resolve) => {
do
解锁全文
加入我们的会员,获取最新、最热、最精彩的开发者技术内容