1. 为什么需要理解异步编程的本质
第一次用Promise的时候,我被then()方法的链式调用惊艳到了。但当我尝试在项目里大量使用async/await时,却遇到了一个诡异的问题:在for循环里使用await,性能居然比同步代码还差!这个反直觉的现象让我意识到,如果不理解异步编程的底层原理,永远只能停留在API调用层面。
现代前端开发中,异步操作无处不在:从简单的setTimeout到复杂的fetch请求,从文件读取到Web Worker通信。理解异步编程的底层机制,不仅能帮我们写出更健壮的代码,还能在性能优化时做出正确决策。本文将带你从零实现Promise开始,逐步揭开JavaScript异步编程的面纱。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. Promise手写实现与核心原理
2.1 最简版Promise构造函数
我们先实现一个能跑通的Promise雏形:
javascript复制class MyPromise {
constructor(executor) {
this.state = 'pending'
this.value = undefined
this.reason = undefined
this.onFulfilledCallbacks = []
this.onRejectedCallbacks = []
const resolve = (value) => {
if (this.state === 'pending') {
this.state = 'fulfilled'
this.value = value
this.onFulfilledCallbacks.forEach(fn => fn())
}
}
const reject = (reason) => {
if (this.state === 'pending') {
this.state = 'rejected'
this.reason = reason
this.onRejectedCallbacks.forEach(fn => fn())
}
}
try {
executor(resolve, reject)
} catch (err) {
reject(err)
}
}
}
这个版本已经实现了Promise最核心的状态管理机制:
- 三种状态:pending/fulfilled/rejected
- 状态不可逆:一旦改变就不能再变
- 异步回调队列:解决回调的异步执行问题
2.2 then方法的链式调用实现
真正的难点在于then方法的实现,它需要处理以下情况:
- 当前Promise可能已经完成或拒绝
- 回调函数可能返回普通值或新的Promise
- 需要支持链式调用
javascript复制then(onFulfilled, onRejected) {
const promise2 = new MyPromise((resolve, reject) => {
const handleFulfilled = () => {
queueMicrotask(() => {
try {
const x = onFulfilled(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (err) {
reject(err)
}
})
}
const handleRejected = () => {
queueMicrotask(() => {
