logo

可能是目前最易理解的手写Promise:从原理到实现全解析

作者:谁偷走了我的奶酪2025.09.19 12:47浏览量:0

简介:本文通过分步拆解Promise核心机制,结合代码示例与状态转换图,用最直观的方式讲解如何手写一个符合A+规范的Promise。涵盖异步任务管理、链式调用、错误处理等关键功能,并提供可运行的完整实现代码。

可能是目前最易理解的手写Promise:从原理到实现全解析

一、为什么需要手写Promise?

在前端开发中,Promise已成为处理异步操作的标准方案。但多数开发者仅停留在then/catch的表面使用,对内部实现机制缺乏深入理解。手写Promise不仅能加深对异步编程的理解,更能帮助解决以下实际问题:

  1. 调试困难:当Promise链中出现意外行为时,理解实现原理能快速定位问题
  2. 性能优化:自定义实现可针对性优化特定场景的异步流程
  3. 框架开发:构建底层库时需要精确控制异步行为
  4. 面试考察:手写Promise是高级前端岗位的常见考察点

本文将通过最简化的实现路径,逐步构建一个符合Promise/A+规范的完整实现,确保每个步骤都有明确的解释。

二、Promise核心机制解析

1. 状态机模型

Promise本质是一个状态机,包含三种状态:

  • Pending(待定):初始状态,可迁移到Fulfilled或Rejected
  • Fulfilled(已兑现):表示操作成功完成
  • Rejected(已拒绝):表示操作失败
  1. const PENDING = 'pending';
  2. const FULFILLED = 'fulfilled';
  3. const REJECTED = 'rejected';
  4. class MyPromise {
  5. constructor(executor) {
  6. this.state = PENDING;
  7. this.value = undefined;
  8. this.reason = undefined;
  9. this.onFulfilledCallbacks = [];
  10. this.onRejectedCallbacks = [];
  11. }
  12. }

状态转换规则:

  1. 只能从Pending迁移到Fulfilled或Rejected
  2. 一旦状态改变,不可再次变更
  3. 状态变更必须通过resolvereject方法触发

2. 异步任务队列

Promise通过维护两个回调队列实现异步处理:

  1. resolve = (value) => {
  2. if (this.state === PENDING) {
  3. this.state = FULFILLED;
  4. this.value = value;
  5. this.onFulfilledCallbacks.forEach(fn => fn());
  6. }
  7. };
  8. reject = (reason) => {
  9. if (this.state === PENDING) {
  10. this.state = REJECTED;
  11. this.reason = reason;
  12. this.onRejectedCallbacks.forEach(fn => fn());
  13. }
  14. };

这种设计确保了:

  • 同步执行的executor函数可以立即触发状态变更
  • 异步执行的executor会将回调推入队列,在微任务中执行

三、分步实现完整Promise

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. // 实现待补充
  10. };
  11. const reject = (reason) => {
  12. // 实现待补充
  13. };
  14. try {
  15. executor(resolve, reject);
  16. } catch (err) {
  17. reject(err);
  18. }
  19. }
  20. }

2. 实现then方法

then方法是Promise的核心,需要处理:

  • 立即返回新Promise实现链式调用
  • 执行时机控制(微任务)
  • 值穿透机制
  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. }

3. 解析Promise链(resolvePromise)

这是实现Promise规范最关键的部分,需要处理:

  • 循环引用检测
  • thenable对象处理
  • 异常捕获
  1. function resolvePromise(promise2, x, resolve, reject) {
  2. // 循环引用检查
  3. if (promise2 === x) {
  4. return reject(new TypeError('Chaining cycle detected for promise'));
  5. }
  6. // 防止多次调用
  7. let called = false;
  8. if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
  9. try {
  10. const then = x.then;
  11. if (typeof then === 'function') {
  12. then.call(
  13. x,
  14. y => {
  15. if (called) return;
  16. called = true;
  17. resolvePromise(promise2, y, resolve, reject);
  18. },
  19. r => {
  20. if (called) return;
  21. called = true;
  22. reject(r);
  23. }
  24. );
  25. } else {
  26. resolve(x);
  27. }
  28. } catch (e) {
  29. if (called) return;
  30. called = true;
  31. reject(e);
  32. }
  33. } else {
  34. resolve(x);
  35. }
  36. }

四、完整实现代码

  1. const PENDING = 'pending';
  2. const FULFILLED = 'fulfilled';
  3. const REJECTED = 'rejected';
  4. class MyPromise {
  5. constructor(executor) {
  6. this.state = PENDING;
  7. this.value = undefined;
  8. this.reason = undefined;
  9. this.onFulfilledCallbacks = [];
  10. this.onRejectedCallbacks = [];
  11. const resolve = (value) => {
  12. if (this.state === PENDING) {
  13. this.state = FULFILLED;
  14. this.value = value;
  15. this.onFulfilledCallbacks.forEach(fn => fn());
  16. }
  17. };
  18. const reject = (reason) => {
  19. if (this.state === PENDING) {
  20. this.state = REJECTED;
  21. this.reason = reason;
  22. this.onRejectedCallbacks.forEach(fn => fn());
  23. }
  24. };
  25. try {
  26. executor(resolve, reject);
  27. } catch (err) {
  28. reject(err);
  29. }
  30. }
  31. then(onFulfilled, onRejected) {
  32. onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
  33. onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason; };
  34. const promise2 = new MyPromise((resolve, reject) => {
  35. const handleFulfilled = () => {
  36. setTimeout(() => {
  37. try {
  38. const x = onFulfilled(this.value);
  39. resolvePromise(promise2, x, resolve, reject);
  40. } catch (e) {
  41. reject(e);
  42. }
  43. }, 0);
  44. };
  45. const handleRejected = () => {
  46. setTimeout(() => {
  47. try {
  48. const x = onRejected(this.reason);
  49. resolvePromise(promise2, x, resolve, reject);
  50. } catch (e) {
  51. reject(e);
  52. }
  53. }, 0);
  54. };
  55. if (this.state === FULFILLED) {
  56. handleFulfilled();
  57. } else if (this.state === REJECTED) {
  58. handleRejected();
  59. } else if (this.state === PENDING) {
  60. this.onFulfilledCallbacks.push(handleFulfilled);
  61. this.onRejectedCallbacks.push(handleRejected);
  62. }
  63. });
  64. return promise2;
  65. }
  66. // 添加catch方法增强实用性
  67. catch(onRejected) {
  68. return this.then(null, onRejected);
  69. }
  70. // 添加静态resolve方法
  71. static resolve(value) {
  72. if (value instanceof MyPromise) {
  73. return value;
  74. }
  75. return new MyPromise(resolve => resolve(value));
  76. }
  77. }
  78. function resolvePromise(promise2, x, resolve, reject) {
  79. if (promise2 === x) {
  80. return reject(new TypeError('Chaining cycle detected for promise'));
  81. }
  82. let called = false;
  83. if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
  84. try {
  85. const then = x.then;
  86. if (typeof then === 'function') {
  87. then.call(
  88. x,
  89. y => {
  90. if (called) return;
  91. called = true;
  92. resolvePromise(promise2, y, resolve, reject);
  93. },
  94. r => {
  95. if (called) return;
  96. called = true;
  97. reject(r);
  98. }
  99. );
  100. } else {
  101. resolve(x);
  102. }
  103. } catch (e) {
  104. if (called) return;
  105. called = true;
  106. reject(e);
  107. }
  108. } else {
  109. resolve(x);
  110. }
  111. }

五、实用建议与扩展

  1. 测试验证:使用Promises/A+测试套件验证实现正确性

    1. npm install promises-aplus-tests -g
    2. promises-aplus-tests your-promise-implementation.js
  2. 性能优化

    • 使用queueMicrotask替代setTimeout实现更精确的微任务调度
    • 对频繁创建的Promise进行对象池管理
  3. 扩展功能

    • 实现finally方法
    • 添加allrace等静态方法
    • 支持取消Promise的机制
  4. 调试技巧

    • 在状态变更时添加日志
    • 实现inspect方法便于调试

六、总结

通过分步实现,我们构建了一个符合Promise/A+规范的完整实现。关键点包括:

  1. 严格的三态管理机制
  2. 异步回调队列的实现
  3. 链式调用的值穿透处理
  4. thenable对象的解析规则

这种实现方式不仅加深了对Promise原理的理解,更为自定义异步控制提供了基础。实际开发中,可根据具体需求在此基础上进行扩展优化,构建更符合业务场景的异步解决方案。

相关文章推荐

发表评论