logo

手写实现Promise:从原理到代码的深度解析

作者:Nicky2025.09.19 12:47浏览量:0

简介:本文深入解析Promise的核心机制,通过手写实现揭示其异步处理、状态管理和链式调用的实现原理,提供可运行的代码示例和关键设计思路。

手写实现Promise:从原理到代码的深度解析

一、Promise的核心机制解析

Promise作为JavaScript异步编程的基石,其核心价值在于统一异步操作的处理范式。原生Promise通过状态机(pending/fulfilled/rejected)和链式调用(then/catch/finally)解决了回调地狱问题。手写实现需理解三个关键特性:

  1. 状态不可逆性:一旦状态从pending变为fulfilled/rejected,不得再次变更
  2. 值穿透机制:then方法返回的新Promise会继承前一个Promise的解析值
  3. 异步调度保障:使用微任务队列(如MutationObserver或setTimeout)确保then回调的执行顺序

典型原生Promise使用示例:

  1. new Promise((resolve) => {
  2. setTimeout(() => resolve(1), 1000)
  3. }).then(res => {
  4. console.log(res) // 1秒后输出1
  5. return res + 1
  6. }).then(console.log) // 输出2

二、基础框架搭建

1. 构造函数实现

  1. class MyPromise {
  2. constructor(executor) {
  3. this.state = 'pending' // 初始状态
  4. this.value = undefined // 成功值
  5. this.reason = undefined // 失败原因
  6. this.onFulfilledCallbacks = [] // 成功回调队列
  7. this.onRejectedCallbacks = [] // 失败回调队列
  8. const resolve = (value) => {
  9. if (this.state === 'pending') {
  10. this.state = 'fulfilled'
  11. this.value = value
  12. this.onFulfilledCallbacks.forEach(fn => fn())
  13. }
  14. }
  15. const reject = (reason) => {
  16. if (this.state === 'pending') {
  17. this.state = 'rejected'
  18. this.reason = reason
  19. this.onRejectedCallbacks.forEach(fn => fn())
  20. }
  21. }
  22. try {
  23. executor(resolve, reject)
  24. } catch (err) {
  25. reject(err)
  26. }
  27. }
  28. }

2. 状态管理要点

  • 三态互斥:通过条件判断确保状态只能变更一次
  • 错误捕获:在executor执行时使用try-catch包裹
  • 异步回调存储:使用数组暂存回调函数,待状态变更后批量执行

三、then方法实现与链式调用

1. then方法核心逻辑

  1. then(onFulfilled, onRejected) {
  2. // 参数默认值处理
  3. onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value
  4. onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason }
  5. const promise2 = new MyPromise((resolve, reject) => {
  6. if (this.state === 'fulfilled') {
  7. setTimeout(() => {
  8. try {
  9. const x = onFulfilled(this.value)
  10. resolvePromise(promise2, x, resolve, reject)
  11. } catch (e) {
  12. reject(e)
  13. }
  14. }, 0)
  15. } else if (this.state === 'rejected') {
  16. setTimeout(() => {
  17. try {
  18. const x = onRejected(this.reason)
  19. resolvePromise(promise2, x, resolve, reject)
  20. } catch (e) {
  21. reject(e)
  22. }
  23. }, 0)
  24. } else if (this.state === 'pending') {
  25. this.onFulfilledCallbacks.push(() => {
  26. setTimeout(() => {
  27. try {
  28. const x = onFulfilled(this.value)
  29. resolvePromise(promise2, x, resolve, reject)
  30. } catch (e) {
  31. reject(e)
  32. }
  33. }, 0)
  34. })
  35. this.onRejectedCallbacks.push(() => {
  36. setTimeout(() => {
  37. try {
  38. const x = onRejected(this.reason)
  39. resolvePromise(promise2, x, resolve, reject)
  40. } catch (e) {
  41. reject(e)
  42. }
  43. }, 0)
  44. })
  45. }
  46. })
  47. return promise2
  48. }

2. 返回值解析关键

resolvePromise函数处理then回调的返回值,需遵循Promise/A+规范:

  1. function resolvePromise(promise2, x, resolve, reject) {
  2. if (promise2 === x) {
  3. return reject(new TypeError('Chaining cycle detected'))
  4. }
  5. let called = false
  6. if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
  7. try {
  8. const then = x.then
  9. if (typeof then === 'function') {
  10. then.call(x,
  11. y => {
  12. if (called) return
  13. called = true
  14. resolvePromise(promise2, y, resolve, reject)
  15. },
  16. r => {
  17. if (called) return
  18. called = true
  19. reject(r)
  20. }
  21. )
  22. } else {
  23. resolve(x)
  24. }
  25. } catch (e) {
  26. if (called) return
  27. called = true
  28. reject(e)
  29. }
  30. } else {
  31. resolve(x)
  32. }
  33. }

四、静态方法实现

1. Promise.resolve/reject

  1. static resolve(value) {
  2. if (value instanceof MyPromise) {
  3. return value
  4. }
  5. return new MyPromise(resolve => resolve(value))
  6. }
  7. static reject(reason) {
  8. return new MyPromise((_, reject) => reject(reason))
  9. }

2. Promise.all实现

  1. static all(promises) {
  2. return new MyPromise((resolve, reject) => {
  3. const results = []
  4. let count = 0
  5. if (promises.length === 0) {
  6. resolve(results)
  7. }
  8. promises.forEach((p, index) => {
  9. MyPromise.resolve(p).then(
  10. value => {
  11. results[index] = value
  12. count++
  13. if (count === promises.length) {
  14. resolve(results)
  15. }
  16. },
  17. reason => reject(reason)
  18. )
  19. })
  20. })
  21. }

五、实际应用与调试技巧

1. 常见问题处理

  • 内存泄漏:确保回调执行后清理事件监听
  • 循环引用:在resolvePromise中检测promise2 === x的情况
  • 微任务模拟:使用MutationObserver替代setTimeout实现更精确的调度

2. 性能优化建议

  1. // 使用Symbol优化状态判断
  2. const STATES = {
  3. PENDING: Symbol('pending'),
  4. FULFILLED: Symbol('fulfilled'),
  5. REJECTED: Symbol('rejected')
  6. }
  7. // 批量执行回调优化
  8. executeCallbacks() {
  9. while(this.onFulfilledCallbacks.length) {
  10. const callback = this.onFulfilledCallbacks.shift()
  11. callback()
  12. }
  13. }

3. 测试用例设计

  1. // 基础功能测试
  2. test('basic then', () => {
  3. return new MyPromise(resolve => resolve(1))
  4. .then(x => x + 1)
  5. .then(x => {
  6. expect(x).toBe(2)
  7. })
  8. })
  9. // 异常处理测试
  10. test('error handling', () => {
  11. const error = new Error('test')
  12. return new MyPromise((_, reject) => reject(error))
  13. .catch(e => {
  14. expect(e).toBe(error)
  15. })
  16. })

六、完整实现代码

[此处可插入完整可运行的代码实现,约200行精简代码]

七、进阶方向

  1. 取消功能:通过AbortController实现Promise取消
  2. 进度通知:扩展onProgress回调机制
  3. 并发控制:实现类似Promise.map的并发限制方法
  4. TypeScript支持:添加完整的类型定义

通过手写实现Promise,开发者不仅能深入理解异步编程的核心机制,更能培养对JavaScript事件循环、闭包、原型链等基础概念的深刻认知。这种实践对于解决复杂异步场景问题、设计可靠的异步库具有重要价值。建议结合ES6规范和Promise/A+测试套件进行验证,确保实现的规范性和稳定性。

相关文章推荐

发表评论