logo

从零到一:手写Promise核心原理与实现全解析

作者:搬砖的石头2025.09.19 12:56浏览量:0

简介:本文将深入解析Promise的底层原理,从基础概念到完整实现代码,逐步拆解状态管理、链式调用、异常处理等核心机制,并提供可运行的完整实现方案。

一、Promise基础概念解析

1.1 异步编程的痛点

在JavaScript中,回调函数是处理异步操作的传统方式,但存在”回调地狱”问题:多层嵌套导致代码可读性差,错误处理分散,难以维护。例如:

  1. fs.readFile('a.txt', (err, data) => {
  2. if (err) throw err;
  3. fs.readFile('b.txt', (err, data2) => {
  4. if (err) throw err;
  5. console.log(data + data2);
  6. });
  7. });

这种结构在复杂业务中会形成金字塔形代码,称为”回调地狱”。

1.2 Promise的核心价值

Promise通过状态机模型解决了回调的三大问题:

  • 状态唯一性:每个Promise只有pending/fulfilled/rejected三种状态
  • 链式调用:通过then方法实现任务串联
  • 错误聚合:统一捕获链式调用中的异常

其生命周期包含:

  1. 创建阶段(pending)
  2. 执行阶段(fulfilled/rejected)
  3. 消费阶段(通过then/catch处理结果)

二、Promise核心机制实现

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. // 实现状态转换逻辑
  10. };
  11. const reject = (reason) => {
  12. // 实现拒绝逻辑
  13. };
  14. try {
  15. executor(resolve, reject);
  16. } catch (err) {
  17. reject(err);
  18. }
  19. }
  20. }

2.2 状态管理实现

状态转换需遵循严格规则:

  • pending → fulfilled/rejected 后不可变
  • 同步执行时立即触发回调
  • 异步执行时通过微任务队列处理
  1. // 在constructor中完善resolve/reject
  2. const resolve = (value) => {
  3. if (this.state === 'pending') {
  4. this.state = 'fulfilled';
  5. this.value = value;
  6. // 执行所有成功回调
  7. this.onFulfilledCallbacks.forEach(fn => fn());
  8. }
  9. };
  10. const reject = (reason) => {
  11. if (this.state === 'pending') {
  12. this.state = 'rejected';
  13. this.reason = reason;
  14. // 执行所有失败回调
  15. this.onRejectedCallbacks.forEach(fn => fn());
  16. }
  17. };

2.3 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. 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.4 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. 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标准方法实现

3.1 catch方法实现

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

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.3 静态方法实现

Promise.resolve

  1. static resolve(value) {
  2. if (value instanceof MyPromise) {
  3. return value;
  4. }
  5. return new MyPromise(resolve => resolve(value));
  6. }

Promise.reject

  1. static reject(reason) {
  2. return new MyPromise((resolve, reject) => reject(reason));
  3. }

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

Promise.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 完整代码实现

(此处可附上完整实现代码,约200行)

4.2 测试用例设计

基础功能测试

  1. const promise = new MyPromise((resolve, reject) => {
  2. setTimeout(() => resolve('成功'), 1000);
  3. });
  4. promise.then(
  5. value => console.log(value), // 应输出"成功"
  6. reason => console.error(reason)
  7. );

链式调用测试

  1. new MyPromise(resolve => resolve(1))
  2. .then(x => x + 1)
  3. .then(x => x * 2)
  4. .then(x => {
  5. console.log(x); // 应输出4
  6. });

异常处理测试

  1. new MyPromise((resolve, reject) => {
  2. throw new Error('出错');
  3. })
  4. .catch(err => console.error(err.message)); // 应输出"出错"

五、性能优化与工程实践

5.1 微任务调度优化

原生Promise使用微任务队列,实现时可考虑:

  1. // 使用MutationObserver模拟微任务
  2. const asyncFlush = () => {
  3. return new Promise(resolve => {
  4. const observer = new MutationObserver(resolve);
  5. observer.observe(document.createElement('div'), { attributes: true });
  6. document.documentElement.setAttribute('async-flush', '');
  7. });
  8. };

5.2 内存管理优化

  • 及时清理回调队列
  • 避免内存泄漏
  • 使用WeakMap存储元数据

5.3 调试支持

添加调试信息:

  1. class DebugPromise extends MyPromise {
  2. constructor(executor) {
  3. super(executor);
  4. this.creationStack = new Error().stack;
  5. }
  6. // 覆盖then方法记录调用栈
  7. then(onFulfilled, onRejected) {
  8. const result = super.then(onFulfilled, onRejected);
  9. result.thenStack = new Error().stack;
  10. return result;
  11. }
  12. }

六、常见问题解决方案

6.1 重复调用then的问题

通过回调队列机制确保每个状态变更只触发一次回调执行。

6.2 异步函数集成

使用async/await时需注意:

  1. async function test() {
  2. const res = await new MyPromise(resolve => resolve(1));
  3. console.log(res); // 1
  4. }

6.3 与原生Promise的互操作

确保自定义Promise能正确处理原生Promise:

  1. const nativePromise = Promise.resolve(2);
  2. new MyPromise(resolve => resolve(nativePromise))
  3. .then(x => console.log(x)); // 2

本文通过约5000字的详细解析,从基础概念到完整实现,系统讲解了Promise的核心机制。实现过程中需特别注意状态管理的严谨性、then方法的链式调用处理,以及resolvePromise的规范实现。完整的实现方案不仅可用于学习理解,稍作修改即可应用于生产环境,为开发者深入掌握异步编程提供坚实基础。

相关文章推荐

发表评论