logo

手写Promise:从原理到实现的全流程解析

作者:da吃一鲸8862025.09.19 12:47浏览量:0

简介:本文深入解析Promise的底层原理,通过手写实现揭示其核心机制,涵盖状态管理、链式调用、错误处理等关键环节,并提供完整代码示例与实用建议。

手写Promise:从原理到实现的全流程解析

一、Promise的核心价值与实现意义

Promise作为现代JavaScript异步编程的核心工具,解决了回调地狱(Callback Hell)问题,提供了更优雅的异步流程控制方式。其核心价值体现在三个方面:

  1. 状态管理:通过Pending/Fulfilled/Rejected三态模型明确异步操作的生命周期
  2. 链式调用:支持.then()方法的连续调用,形成可读性强的异步代码流
  3. 错误处理:集中式的catch机制替代分散的错误回调

手写Promise的实现过程,本质上是理解异步编程范式转换的关键路径。相比直接使用原生Promise,手动实现能帮助开发者

  • 深入掌握事件循环(Event Loop)与微任务(Microtask)的交互机制
  • 理解thenable对象的兼容性处理
  • 掌握Promise规范(Promises/A+)的核心要求

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

关键点解析

  • 状态机设计:严格限制状态只能从pending转为fulfilled/rejected
  • 异步回调队列:解决then方法调用时机早于resolve/reject的问题
  • 错误捕获:在executor执行时使用try-catch包裹

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

实现要点

  • 异步执行:使用setTimeout模拟微任务队列(实际实现应使用queueMicrotask)
  • 返回值处理:通过resolvePromise处理thenable对象和循环引用
  • 链式调用:每次then返回新Promise实例

三、核心算法:resolvePromise实现

  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 ((typeof x === 'object' && x !== null) || 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. 类型检查:严格区分普通值与thenable对象
  2. 安全调用:使用called标志防止多次resolve/reject
  3. 递归解析:对thenable对象进行深度解析
  4. 异常捕获:处理then方法执行时的潜在错误

四、完整类方法实现

1. catch方法实现

  1. catch(onRejected) {
  2. return this.then(null, onRejected);
  3. }

2. finally方法实现

  1. finally(callback) {
  2. return this.then(
  3. value => MyPromise.resolve(callback()).then(() => value),
  4. reason => MyPromise.resolve(callback()).then(() => { throw reason })
  5. );
  6. }

3. 静态方法实现

  1. // 静态resolve方法
  2. static resolve(value) {
  3. if (value instanceof MyPromise) {
  4. return value;
  5. }
  6. return new MyPromise(resolve => resolve(value));
  7. }
  8. // 静态reject方法
  9. static reject(reason) {
  10. return new MyPromise((resolve, reject) => reject(reason));
  11. }
  12. // 静态all方法
  13. static all(promises) {
  14. return new MyPromise((resolve, reject) => {
  15. const results = [];
  16. let count = 0;
  17. if (promises.length === 0) {
  18. resolve(results);
  19. }
  20. promises.forEach((promise, index) => {
  21. MyPromise.resolve(promise).then(
  22. value => {
  23. results[index] = value;
  24. count++;
  25. if (count === promises.length) {
  26. resolve(results);
  27. }
  28. },
  29. reason => reject(reason)
  30. );
  31. });
  32. });
  33. }
  34. // 静态race方法
  35. static race(promises) {
  36. return new MyPromise((resolve, reject) => {
  37. promises.forEach(promise => {
  38. MyPromise.resolve(promise).then(resolve, reject);
  39. });
  40. });
  41. }

五、实现验证与测试用例

1. 基础功能测试

  1. // 测试1:基本用法
  2. const promise = new MyPromise((resolve) => {
  3. setTimeout(() => resolve('成功'), 1000);
  4. });
  5. promise.then(
  6. value => console.log(value), // 应输出"成功"
  7. reason => console.error(reason)
  8. );
  9. // 测试2:链式调用
  10. MyPromise.resolve(1)
  11. .then(x => x + 1)
  12. .then(x => x * 2)
  13. .then(console.log); // 应输出4

2. 边界条件测试

  1. // 测试3:thenable对象处理
  2. const thenable = {
  3. then: function(resolve, reject) {
  4. resolve('thenable成功');
  5. }
  6. };
  7. MyPromise.resolve(thenable).then(console.log); // 应输出"thenable成功"
  8. // 测试4:循环引用检测
  9. const badPromise = new MyPromise(resolve => resolve());
  10. badPromise.then(() => badPromise).then(() => {}, err => {
  11. console.log(err.message); // 应输出"Chaining cycle detected"
  12. });

3. 静态方法测试

  1. // 测试5:Promise.all
  2. const p1 = MyPromise.resolve(1);
  3. const p2 = MyPromise.resolve(2);
  4. const p3 = MyPromise.resolve(3);
  5. MyPromise.all([p1, p2, p3]).then(values => {
  6. console.log(values); // 应输出[1, 2, 3]
  7. });
  8. // 测试6:Promise.race
  9. const fast = new MyPromise(resolve => setTimeout(() => resolve('快速'), 100));
  10. const slow = new MyPromise(resolve => setTimeout(() => resolve('慢速'), 1000));
  11. MyPromise.race([slow, fast]).then(value => {
  12. console.log(value); // 应输出"快速"
  13. });

六、实践建议与优化方向

  1. 性能优化

    • 使用MutationObserver或MessageChannel替代setTimeout模拟微任务
    • 对高频调用的Promise进行批处理优化
  2. 调试支持

    1. // 添加调试信息
    2. constructor(executor) {
    3. this._traceId = Date.now() + '-' + Math.random().toString(36).substr(2);
    4. // ...原有实现
    5. }
    6. static debug(promise) {
    7. console.log(`[Promise Debug] ${promise._traceId} state: ${promise.state}`);
    8. }
  3. 取消功能扩展

    1. class CancelablePromise extends MyPromise {
    2. constructor(executor) {
    3. super((resolve, reject) => {
    4. this._cancel = () => reject(new CancelError('Promise canceled'));
    5. executor(resolve, reject);
    6. });
    7. }
    8. cancel() {
    9. if (this._cancel) this._cancel();
    10. }
    11. }
  4. TypeScript支持

    1. interface Thenable<T> {
    2. then<U>(
    3. onFulfilled?: (value: T) => U | Thenable<U>,
    4. onRejected?: (reason: any) => U | Thenable<U>
    5. ): Thenable<U>;
    6. }
    7. class MyPromise<T> implements Thenable<T> {
    8. // ...实现代码
    9. }

七、总结与展望

手写Promise的实现过程,本质上是掌握异步编程范式转换的实践路径。通过完整实现,开发者可以:

  1. 深入理解事件循环与任务队列的交互机制
  2. 掌握函数式编程在异步场景的应用技巧
  3. 提升对Promise规范(Promises/A+)的解读能力

未来发展方向可关注:

  • Async/Await的语法糖实现原理
  • 响应式编程(如RxJS)与Promise的融合
  • WebAssembly环境下的Promise实现优化

建议开发者在实现过程中,严格对照Promises/A+规范进行测试验证,确保实现的兼容性和健壮性。实际项目开发中,推荐在理解原理的基础上使用原生Promise或成熟的库(如Bluebird),以获得更好的性能和浏览器兼容性。

相关文章推荐

发表评论