手写实现Promise:从原理到代码的深度解析
2025.09.19 12:47浏览量:0简介:本文深入解析Promise的核心机制,通过手写实现揭示其异步处理、状态管理和链式调用的实现原理,提供可运行的代码示例和关键设计思路。
手写实现Promise:从原理到代码的深度解析
一、Promise的核心机制解析
Promise作为JavaScript异步编程的基石,其核心价值在于统一异步操作的处理范式。原生Promise通过状态机(pending/fulfilled/rejected)和链式调用(then/catch/finally)解决了回调地狱问题。手写实现需理解三个关键特性:
- 状态不可逆性:一旦状态从pending变为fulfilled/rejected,不得再次变更
- 值穿透机制:then方法返回的新Promise会继承前一个Promise的解析值
- 异步调度保障:使用微任务队列(如MutationObserver或setTimeout)确保then回调的执行顺序
典型原生Promise使用示例:
new Promise((resolve) => {
setTimeout(() => resolve(1), 1000)
}).then(res => {
console.log(res) // 1秒后输出1
return res + 1
}).then(console.log) // 输出2
二、基础框架搭建
1. 构造函数实现
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)
}
}
}
2. 状态管理要点
- 三态互斥:通过条件判断确保状态只能变更一次
- 错误捕获:在executor执行时使用try-catch包裹
- 异步回调存储:使用数组暂存回调函数,待状态变更后批量执行
三、then方法实现与链式调用
1. then方法核心逻辑
then(onFulfilled, onRejected) {
// 参数默认值处理
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value
onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason }
const promise2 = new MyPromise((resolve, reject) => {
if (this.state === 'fulfilled') {
setTimeout(() => {
try {
const x = onFulfilled(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
} else if (this.state === 'rejected') {
setTimeout(() => {
try {
const x = onRejected(this.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
} else if (this.state === 'pending') {
this.onFulfilledCallbacks.push(() => {
setTimeout(() => {
try {
const x = onFulfilled(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
})
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
const x = onRejected(this.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
})
}
})
return promise2
}
2. 返回值解析关键
resolvePromise
函数处理then回调的返回值,需遵循Promise/A+规范:
function resolvePromise(promise2, x, resolve, reject) {
if (promise2 === x) {
return reject(new TypeError('Chaining cycle detected'))
}
let called = false
if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
try {
const then = x.then
if (typeof then === 'function') {
then.call(x,
y => {
if (called) return
called = true
resolvePromise(promise2, y, resolve, reject)
},
r => {
if (called) return
called = true
reject(r)
}
)
} else {
resolve(x)
}
} catch (e) {
if (called) return
called = true
reject(e)
}
} else {
resolve(x)
}
}
四、静态方法实现
1. Promise.resolve/reject
static resolve(value) {
if (value instanceof MyPromise) {
return value
}
return new MyPromise(resolve => resolve(value))
}
static reject(reason) {
return new MyPromise((_, reject) => reject(reason))
}
2. Promise.all实现
static all(promises) {
return new MyPromise((resolve, reject) => {
const results = []
let count = 0
if (promises.length === 0) {
resolve(results)
}
promises.forEach((p, index) => {
MyPromise.resolve(p).then(
value => {
results[index] = value
count++
if (count === promises.length) {
resolve(results)
}
},
reason => reject(reason)
)
})
})
}
五、实际应用与调试技巧
1. 常见问题处理
- 内存泄漏:确保回调执行后清理事件监听
- 循环引用:在resolvePromise中检测promise2 === x的情况
- 微任务模拟:使用MutationObserver替代setTimeout实现更精确的调度
2. 性能优化建议
// 使用Symbol优化状态判断
const STATES = {
PENDING: Symbol('pending'),
FULFILLED: Symbol('fulfilled'),
REJECTED: Symbol('rejected')
}
// 批量执行回调优化
executeCallbacks() {
while(this.onFulfilledCallbacks.length) {
const callback = this.onFulfilledCallbacks.shift()
callback()
}
}
3. 测试用例设计
// 基础功能测试
test('basic then', () => {
return new MyPromise(resolve => resolve(1))
.then(x => x + 1)
.then(x => {
expect(x).toBe(2)
})
})
// 异常处理测试
test('error handling', () => {
const error = new Error('test')
return new MyPromise((_, reject) => reject(error))
.catch(e => {
expect(e).toBe(error)
})
})
六、完整实现代码
[此处可插入完整可运行的代码实现,约200行精简代码]
七、进阶方向
- 取消功能:通过AbortController实现Promise取消
- 进度通知:扩展onProgress回调机制
- 并发控制:实现类似Promise.map的并发限制方法
- TypeScript支持:添加完整的类型定义
通过手写实现Promise,开发者不仅能深入理解异步编程的核心机制,更能培养对JavaScript事件循环、闭包、原型链等基础概念的深刻认知。这种实践对于解决复杂异步场景问题、设计可靠的异步库具有重要价值。建议结合ES6规范和Promise/A+测试套件进行验证,确保实现的规范性和稳定性。
发表评论
登录后可评论,请前往 登录 或 注册