logo

从零开始:手写实现Promise核心机制解析

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

简介:本文深入解析Promise核心机制,通过手写实现完整功能,涵盖状态管理、链式调用、异步处理等关键特性,帮助开发者理解其底层原理。

从零开始:手写实现Promise核心机制解析

Promise作为JavaScript异步编程的核心解决方案,其设计思想深刻影响了现代前端开发。本文将通过手写实现一个简化版Promise,深入解析其工作原理,帮助开发者理解状态管理、链式调用、异步处理等核心机制。

一、Promise基础架构设计

1.1 核心状态定义

Promise规范定义了三种状态:pendingfulfilledrejected。状态转换具有单向性:

  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. }

状态机设计确保了Promise的确定性行为,这是链式调用和异常处理的基础。

1.2 执行器函数解析

执行器函数接收resolvereject两个参数,这两个方法需要处理状态变更和回调执行:

  1. resolve = (value) => {
  2. if (this.state === PENDING) {
  3. this.state = FULFILLED;
  4. this.value = value;
  5. // 执行所有成功回调
  6. this.onFulfilledCallbacks.forEach(fn => fn());
  7. }
  8. };
  9. reject = (reason) => {
  10. if (this.state === PENDING) {
  11. this.state = REJECTED;
  12. this.reason = reason;
  13. // 执行所有失败回调
  14. this.onRejectedCallbacks.forEach(fn => fn());
  15. }
  16. };

异步执行要求通过try/catch包裹执行器,防止未捕获异常导致进程崩溃。

二、核心方法实现

2.1 then方法实现

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. // 模拟异步执行
  8. setTimeout(() => {
  9. try {
  10. const x = onFulfilled(this.value);
  11. resolvePromise(promise2, x, resolve, reject);
  12. } catch (e) {
  13. reject(e);
  14. }
  15. }, 0);
  16. } else if (this.state === REJECTED) {
  17. setTimeout(() => {
  18. try {
  19. const x = onRejected(this.reason);
  20. resolvePromise(promise2, x, resolve, reject);
  21. } catch (e) {
  22. reject(e);
  23. }
  24. }, 0);
  25. } else if (this.state === PENDING) {
  26. this.onFulfilledCallbacks.push(() => {
  27. setTimeout(() => {
  28. try {
  29. const x = onFulfilled(this.value);
  30. resolvePromise(promise2, x, resolve, reject);
  31. } catch (e) {
  32. reject(e);
  33. }
  34. }, 0);
  35. });
  36. this.onRejectedCallbacks.push(() => {
  37. setTimeout(() => {
  38. try {
  39. const x = onRejected(this.reason);
  40. resolvePromise(promise2, x, resolve, reject);
  41. } catch (e) {
  42. reject(e);
  43. }
  44. }, 0);
  45. });
  46. }
  47. });
  48. return promise2;
  49. }

通过返回新的Promise实例实现链式调用,使用setTimeout模拟微任务队列。

2.2 resolvePromise解析

处理thenable对象和Promise的递归解析是关键:

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

该实现遵循Promise/A+规范,处理了各种边界情况。

三、静态方法实现

3.1 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((resolve, reject) => reject(reason));
  9. }

3.2 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((promise, index) => {
  9. MyPromise.resolve(promise).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. }

3.3 race方法实现

  1. static race(promises) {
  2. return new MyPromise((resolve, reject) => {
  3. promises.forEach(promise => {
  4. MyPromise.resolve(promise).then(resolve, reject);
  5. });
  6. });
  7. }

四、实际应用与调试技巧

4.1 常见问题排查

  1. 状态不可变:确保状态只能从pending转为fulfilled/rejected一次
  2. 回调执行顺序:使用setTimeout模拟微任务队列
  3. 值穿透处理:then方法的可选参数处理

4.2 性能优化建议

  1. 使用数组存储回调而非多次push
  2. 对已决议的Promise立即执行回调
  3. 实现微任务队列(实际开发中可使用MutationObserver或MessageChannel)

4.3 测试用例设计

  1. // 基础测试
  2. const p = new MyPromise((resolve) => {
  3. setTimeout(() => resolve(1), 100);
  4. });
  5. p.then(value => {
  6. console.log(value); // 1
  7. return value + 1;
  8. }).then(value => {
  9. console.log(value); // 2
  10. });
  11. // 异常处理测试
  12. MyPromise.reject('error')
  13. .catch(e => {
  14. console.log(e); // 'error'
  15. return 'recovered';
  16. })
  17. .then(v => console.log(v)); // 'recovered'

五、完整实现代码

  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 (e) {
  28. reject(e);
  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. if (this.state === FULFILLED) {
  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. } else if (this.state === REJECTED) {
  45. setTimeout(() => {
  46. try {
  47. const x = onRejected(this.reason);
  48. resolvePromise(promise2, x, resolve, reject);
  49. } catch (e) {
  50. reject(e);
  51. }
  52. }, 0);
  53. } else if (this.state === PENDING) {
  54. this.onFulfilledCallbacks.push(() => {
  55. setTimeout(() => {
  56. try {
  57. const x = onFulfilled(this.value);
  58. resolvePromise(promise2, x, resolve, reject);
  59. } catch (e) {
  60. reject(e);
  61. }
  62. }, 0);
  63. });
  64. this.onRejectedCallbacks.push(() => {
  65. setTimeout(() => {
  66. try {
  67. const x = onRejected(this.reason);
  68. resolvePromise(promise2, x, resolve, reject);
  69. } catch (e) {
  70. reject(e);
  71. }
  72. }, 0);
  73. });
  74. }
  75. });
  76. return promise2;
  77. }
  78. catch(onRejected) {
  79. return this.then(null, onRejected);
  80. }
  81. finally(callback) {
  82. return this.then(
  83. value => MyPromise.resolve(callback()).then(() => value),
  84. reason => MyPromise.resolve(callback()).then(() => { throw reason; })
  85. );
  86. }
  87. static resolve(value) {
  88. if (value instanceof MyPromise) {
  89. return value;
  90. }
  91. return new MyPromise(resolve => resolve(value));
  92. }
  93. static reject(reason) {
  94. return new MyPromise((resolve, reject) => reject(reason));
  95. }
  96. static all(promises) {
  97. return new MyPromise((resolve, reject) => {
  98. const results = [];
  99. let count = 0;
  100. if (promises.length === 0) {
  101. resolve(results);
  102. }
  103. promises.forEach((promise, index) => {
  104. MyPromise.resolve(promise).then(
  105. value => {
  106. results[index] = value;
  107. count++;
  108. if (count === promises.length) {
  109. resolve(results);
  110. }
  111. },
  112. reason => reject(reason)
  113. );
  114. });
  115. });
  116. }
  117. static race(promises) {
  118. return new MyPromise((resolve, reject) => {
  119. promises.forEach(promise => {
  120. MyPromise.resolve(promise).then(resolve, reject);
  121. });
  122. });
  123. }
  124. }
  125. function resolvePromise(promise2, x, resolve, reject) {
  126. if (promise2 === x) {
  127. return reject(new TypeError('Chaining cycle detected for promise'));
  128. }
  129. let called = false;
  130. if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
  131. try {
  132. const then = x.then;
  133. if (typeof then === 'function') {
  134. then.call(
  135. x,
  136. y => {
  137. if (called) return;
  138. called = true;
  139. resolvePromise(promise2, y, resolve, reject);
  140. },
  141. r => {
  142. if (called) return;
  143. called = true;
  144. reject(r);
  145. }
  146. );
  147. } else {
  148. resolve(x);
  149. }
  150. } catch (e) {
  151. if (called) return;
  152. called = true;
  153. reject(e);
  154. }
  155. } else {
  156. resolve(x);
  157. }
  158. }

总结

通过手写实现Promise,我们深入理解了其状态管理、链式调用和异步处理机制。关键实现要点包括:

  1. 严格的状态转换规则
  2. 回调队列的异步执行
  3. thenable对象的递归解析
  4. 静态方法的完整实现

这种实现虽然简化了部分细节(如真正的微任务调度),但完整遵循了Promise/A+规范的核心逻辑。开发者可以通过扩展这个基础实现,添加async/await支持、取消功能等高级特性,进一步加深对异步编程的理解。

相关文章推荐

发表评论