深入理解Promise:从简单版到完整版的手写实现

89 阅读10分钟

前言

Promise作为JavaScript异步编程的核心概念,是现代前端开发中不可或缺的重要知识点。本文将手写两个版本的Promise实现:一个简单版和一个完整版,帮助你彻底掌握Promise的内部机制。

什么是Promise?

Promise是一种异步编程的解决方案,用于处理异步操作的结果。它具有以下特点:

  • 三种状态:pending(等待中)、fulfilled(已成功)、rejected(已失败)
  • 状态不可逆:状态一旦改变,就不能再变
  • 链式调用:可以避免回调地狱
  • 统一的错误处理:提供了catch方法进行错误捕获

简单版Promise实现

我们先从一个最简单的Promise实现开始,理解Promise的基本结构:

class simplePromise {
  constructor(excutor) {
    // Promise的三种状态:pending(等待中)、fulfilled(已成功)、rejected(已失败)
    this.status = 'pending' // 初始状态为pending
    this.value = undefined  // 存储成功时的返回值
    this.reason = undefined // 存储失败时的原因
    this.onFulfilledCallbacks = [] // 存储成功回调函数的队列
    this.onRejectedCallbacks = []  // 存储失败回调函数的队列

    // resolve函数:将Promise状态从pending改为fulfilled
    const resolve = (value) => {
      // 只有在pending状态下才能改变状态(状态不可逆)
      if (this.status === 'pending') {
        this.status = 'fulfilled' // 更新状态为fulfilled
        this.value = value        // 存储成功的值
        // 执行所有已注册的成功回调函数
        this.onFulfilledCallbacks.forEach(fn => fn(this.value))
      }
    }
    
    // reject函数:将Promise状态从pending改为rejected
    const reject = (reason) => {
      if (this.status === 'pending') {
        this.status = 'rejected' // 更新状态为rejected
        this.reason = reason      // 存储失败的原因
        // 执行所有已注册的失败回调函数
        this.onRejectedCallbacks.forEach(fn => fn(this.reason))
      }
    }

    // 立即执行executor函数,捕获可能的同步错误
    try {
      excutor(resolve, reject) // 将resolve和reject函数作为参数传入
    } catch (error) {
      // 如果executor执行过程中抛出错误,直接调用reject
      reject(error)
    }
  }

  // then方法:添加成功和失败的回调函数,支持链式调用
  then(onFulfilled, onRejected) {
    // 处理参数可能不是函数的情况(值穿透)
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value
    onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason }

    // 返回新的Promise实例,实现链式调用
    return new simplePromise((resolve, reject) => {
      // 处理fulfilled状态的函数
      const handleFulfilled = () => {
        try {
          // 执行成功回调,获取返回值
          const result = onFulfilled(this.value)
          // 将返回值传递给新的Promise
          resolve(result)
        } catch (error) {
          // 如果回调执行出错,reject错误
          reject(error)
        }
      }
      
      // 处理rejected状态的函数
      const handleRejected = () => {
        try {
          // 执行失败回调,获取返回值
          const result = onRejected(this.reason)
          // 将返回值传递给新的Promise(即使失败回调也可能返回成功值)
          resolve(result)
        } catch (error) {
          reject(error)
        }
      }

      // 根据当前Promise的状态执行相应的处理
      if (this.status === 'fulfilled') {
        // 如果当前Promise已经是fulfilled状态,立即执行成功回调
        handleFulfilled()
      } else if (this.status === 'rejected') {
        // 如果当前Promise已经是rejected状态,立即执行失败回调
        handleRejected()
      } else if (this.status === 'pending') {
        // 如果当前Promise还是pending状态,将回调函数加入队列等待执行
        this.onFulfilledCallbacks.push(handleFulfilled)
        this.onRejectedCallbacks.push(handleRejected)
      }
    })
  }
}

简单版实现要点解析:

  1. 状态管理:通过status属性管理三种状态
  2. 回调队列:使用数组存储pending状态下的回调函数
  3. then方法:返回新的Promise实例,支持链式调用
  4. 错误处理:使用try-catch捕获执行过程中的错误

完整版Promise实现(符合Promise/A+规范)

接下来我们实现一个符合Promise/A+规范的完整版本,包含所有常用方法:

// Promise的三种状态常量定义
const PENDING = 'pending';    // 等待中:初始状态
const FULFILLED = 'fulfilled'; // 已成功:操作成功完成
const REJECTED = 'rejected';   // 已失败:操作失败

class MyPromise {
  constructor(executor) {
    // 初始化Promise实例的状态和值
    this.status = PENDING;                    // 初始状态为pending
    this.value = null;                        // 存储成功时的值
    this.reason = null;                       // 存储失败时的原因
    this.onFulfilledCallbacks = [];           // 成功回调函数队列
    this.onRejectedCallbacks = [];            // 失败回调函数队列
    
    // resolve函数:将Promise状态从pending改为fulfilled
    const resolve = (value) => {
      // 只有在pending状态下才能改变状态(状态不可逆原则)
      if (this.status === PENDING) {
        this.status = FULFILLED;              // 更新状态为fulfilled
        this.value = value;                   // 存储成功的值
        // 异步执行所有已注册的成功回调函数
        this.onFulfilledCallbacks.forEach(callback => callback());
      }
    };
    
    // reject函数:将Promise状态从pending改为rejected
    const reject = (reason) => {
      if (this.status === PENDING) {
        this.status = REJECTED;               // 更新状态为rejected
        this.reason = reason;                 // 存储失败的原因
        // 异步执行所有已注册的失败回调函数
        this.onRejectedCallbacks.forEach(callback => callback());
      }
    };
    
    // 立即同步执行executor函数,捕获可能的同步错误
    try {
      executor(resolve, reject);             // 传入resolve和reject函数
    } catch (error) {
      // 如果executor执行过程中抛出同步错误,直接调用reject
      reject(error);
    }
  }
  
  // then方法:Promise的核心方法,用于添加成功和失败的回调,支持链式调用
  then(onFulfilled, onRejected) {
    // 处理参数可能不是函数的情况(值穿透机制)
    // 如果onFulfilled不是函数,创建一个默认函数直接返回value
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
    // 如果onRejected不是函数,创建一个默认函数抛出reason
    onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason; };
    
    // 创建新的Promise实例(promise2),用于链式调用
    const promise2 = new MyPromise((resolve, reject) => {
      // 处理当前Promise已经是fulfilled状态的情况
      if (this.status === FULFILLED) {
        // 使用setTimeout确保回调异步执行(符合Promise/A+规范)
        setTimeout(() => {
          try {
            // 执行成功回调函数,获取返回值x
            const x = onFulfilled(this.value);
            // 处理返回值,确保链式调用的正确性
            resolvePromise(promise2, x, resolve, reject);
          } catch (error) {
            // 如果回调执行过程中抛出错误,直接reject
            reject(error);
          }
        }, 0);
      }
      
      // 处理当前Promise已经是rejected状态的情况
      if (this.status === REJECTED) {
        setTimeout(() => {
          try {
            // 执行失败回调函数,获取返回值x
            const x = onRejected(this.reason);
            // 处理返回值
            resolvePromise(promise2, x, resolve, reject);
          } catch (error) {
            reject(error);
          }
        }, 0);
      }
      
      // 处理当前Promise还是pending状态的情况
      if (this.status === PENDING) {
        // 将成功回调包装后加入队列,等待状态改变时执行
        this.onFulfilledCallbacks.push(() => {
          setTimeout(() => {
            try {
              const x = onFulfilled(this.value);
              resolvePromise(promise2, x, resolve, reject);
            } catch (error) {
              reject(error);
            }
          }, 0);
        });
        
        // 将失败回调包装后加入队列,等待状态改变时执行
        this.onRejectedCallbacks.push(() => {
          setTimeout(() => {
            try {
              const x = onRejected(this.reason);
              resolvePromise(promise2, x, resolve, reject);
            } catch (error) {
              reject(error);
            }
          }, 0);
        });
      }
    });
    
    // 返回新的Promise实例,实现链式调用
    return promise2;
  }
  
  // catch方法:处理Promise链中的错误,是then(null, onRejected)的语法糖
  // 用于捕获Promise链中任何位置的错误,简化错误处理代码
  catch(onRejected) {
    // 调用then方法,第一个参数传null,只处理rejected状态
    return this.then(null, onRejected);
  }
  
  // finally方法:无论Promise成功或失败都会执行的回调
  // 常用于清理操作,如关闭数据库连接、隐藏加载动画等
  finally(onFinally) {
    return this.then(
      // 成功时:执行callback,然后返回原始value
      value => MyPromise.resolve(onFinally()).then(() => value),
      // 失败时:执行callback,然后重新抛出原始reason
      reason => MyPromise.resolve(onFinally()).then(() => { throw reason; })
    );
  }
  
  // 静态方法:Promise.resolve - 创建一个已解决的Promise
  // 如果传入的值已经是Promise,直接返回;否则包装成已解决的Promise
  static resolve(value) {
    if (value instanceof MyPromise) {
      return value; // 已经是Promise,直接返回
    }
    // 包装普通值为已解决的Promise
    return new MyPromise(resolve => resolve(value));
  }
  
  // 静态方法:Promise.reject - 创建一个已拒绝的Promise
  // 直接返回一个立即拒绝的Promise实例
  static reject(reason) {
    return new MyPromise((resolve, reject) => reject(reason));
  }
  
  // 静态方法:Promise.all - 等待所有Promise完成
  // 所有Promise都成功时返回结果数组,任何一个失败立即拒绝
  static all(promises) {
    return new MyPromise((resolve, reject) => {
      const results = []; // 存储所有Promise的结果
      let count = 0; // 计数器,记录已完成的Promise数量
      
      // 处理空数组情况
      if (promises.length === 0) {
        return resolve(results); // 空数组直接返回空结果
      }
      
      // 遍历所有Promise
      promises.forEach((promise, index) => {
        // 确保每个元素都是Promise(使用Promise.resolve包装)
        MyPromise.resolve(promise).then(
          // 成功回调:将结果存入对应位置
          value => {
            results[index] = value; // 保持结果顺序与输入一致
            count++;
            // 检查是否所有Promise都已完成
            if (count === promises.length) {
              resolve(results); // 全部成功,返回结果数组
            }
          },
          // 失败回调:任何一个失败立即拒绝整个Promise
          reject
        );
      });
    });
  }
  
  // 静态方法:Promise.race - 竞速,返回最先完成的Promise结果
  // 无论是成功还是失败,第一个完成的Promise决定最终结果
  static race(promises) {
    return new MyPromise((resolve, reject) => {
      // 处理空数组情况
      if (promises.length === 0) {
        return; // 空数组,Promise永远pending
      }
      
      // 遍历所有Promise,第一个完成的决定最终结果
      promises.forEach(promise => {
        MyPromise.resolve(promise).then(resolve, reject);
      });
    });
  }
  
  // 静态方法:Promise.allSettled - 等待所有Promise完成(无论成功失败)
  // 返回包含所有Promise状态和结果的对象数组
  static allSettled(promises) {
    return new MyPromise(resolve => {
      const results = []; // 存储所有Promise的状态和结果
      let count = 0; // 计数器
      
      if (promises.length === 0) {
        return resolve(results); // 空数组直接返回
      }
      
      promises.forEach((promise, index) => {
        MyPromise.resolve(promise).then(
          // 成功:记录fulfilled状态和值
          value => {
            results[index] = { status: FULFILLED, value };
            count++;
            if (count === promises.length) {
              resolve(results);
            }
          },
          // 失败:记录rejected状态和原因
          reason => {
            results[index] = { status: REJECTED, reason };
            count++;
            if (count === promises.length) {
              resolve(results);
            }
          }
        );
      });
    });
  }
  
  // 静态方法:Promise.any - 返回第一个成功的Promise
  // 如果所有Promise都失败,返回AggregateError包含所有错误
  static any(promises) {
    return new MyPromise((resolve, reject) => {
      const errors = []; // 存储所有失败的原因
      let count = 0; // 计数器
      
      if (promises.length === 0) {
        // 空数组,返回包含空错误数组的AggregateError
        return reject(new AggregateError([], 'All promises were rejected'));
      }
      
      promises.forEach((promise, index) => {
        MyPromise.resolve(promise).then(
          // 成功:立即resolve第一个成功的Promise
          resolve,
          // 失败:记录错误,检查是否所有Promise都失败
          reason => {
            errors[index] = reason; // 记录每个Promise的失败原因
            count++;
            // 所有Promise都失败时,返回AggregateError
            if (count === promises.length) {
              reject(new AggregateError(errors, 'All promises were rejected'));
            }
          }
        );
      });
    });
  }
}

// resolvePromise函数:处理Promise链式调用中的返回值,确保符合Promise/A+规范
// 这是Promise实现中最复杂的部分,负责处理then方法返回值的各种情况
function resolvePromise(promise2, x, resolve, reject) {
  // 检查循环引用:如果promise2和x是同一个对象,抛出TypeError
  // 防止出现 promise.then(() => promise) 这样的循环引用
  if (promise2 === x) {
    return reject(new TypeError('Chaining cycle detected for promise'));
  }
  
  // 标记是否已经调用过resolve或reject,确保只调用一次
  let called = false;
  
  // 如果x是对象或函数(可能是Promise或thenable对象)
  if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
    try {
      // 获取x的then方法(如果x是Promise,then方法应该存在)
      const then = x.then;
      // 如果then是函数,将x视为Promise或thenable对象
      if (typeof then === 'function') {
        // 调用x的then方法,传入resolve和reject回调
        then.call(
          x,
          // resolve回调:当x成功时,递归调用resolvePromise处理返回值y
          y => {
            if (called) return; // 确保只调用一次
            called = true;
            // 递归处理y,因为y可能也是一个Promise
            resolvePromise(promise2, y, resolve, reject);
          },
          // reject回调:当x失败时,直接reject原因r
          r => {
            if (called) return; // 确保只调用一次
            called = true;
            reject(r);
          }
        );
      } else {
        // 如果then不是函数,说明x是普通对象,直接resolve
        resolve(x);
      }
    } catch (error) {
      // 如果获取then或调用then时出错,直接reject错误
      if (called) return; // 确保只调用一次
      called = true;
      reject(error);
    }
  } else {
    // 如果x不是对象或函数(是基本类型值),直接resolve
    resolve(x);
  }
}

核心实现要点解析

1. 状态管理机制

Promise的状态管理是其核心特性之一:

const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

// 状态一旦改变,就不能再变
if (this.status === PENDING) {
  this.status = FULFILLED; // 或 REJECTED
  // ...
}

2. 异步执行保证

为了符合Promise/A+规范,then方法的回调必须异步执行:

setTimeout(() => {
  // 异步执行回调
  const x = onFulfilled(this.value);
  resolvePromise(promise2, x, resolve, reject);
}, 0);

3. 链式调用实现

then方法返回新的Promise实例,实现链式调用:

then(onFulfilled, onRejected) {
  const promise2 = new MyPromise((resolve, reject) => {
    // ...
  });
  return promise2;
}

4. Promise解析过程

resolvePromise函数处理then方法返回值的各种情况:

  • 普通值:直接resolve
  • Promise对象:等待其状态改变
  • thenable对象:调用其then方法
  • 循环引用:抛出TypeError

常用静态方法实现

Promise.resolve()

将值转换为Promise对象:

static resolve(value) {
  if (value instanceof MyPromise) {
    return value;
  }
  return new MyPromise((resolve) => {
    resolve(value);
  });
}

Promise.all()

等待所有Promise完成:

static all(promises) {
  return new MyPromise((resolve, reject) => {
    const results = [];
    let count = 0;
    
    promises.forEach((promise, index) => {
      MyPromise.resolve(promise).then(
        value => {
          results[index] = value;
          count++;
          if (count === promises.length) {
            resolve(results);
          }
        },
        reject
      );
    });
  });
}

Promise.race()

返回第一个完成的Promise:

static race(promises) {
  return new MyPromise((resolve, reject) => {
    promises.forEach(promise => {
      MyPromise.resolve(promise).then(resolve, reject);
    });
  });
}

测试用例

让我们测试一下实现的正确性:

// 基本功能测试
const promise1 = new MyPromise((resolve, reject) => {
  setTimeout(() => {
    resolve('成功了!');
  }, 1000);
});

promise1.then(
  value => console.log('成功:', value),
  reason => console.log('失败:', reason)
);

// 链式调用测试
new MyPromise((resolve) => setTimeout(() => resolve(1), 1000))
  .then(value => {
    console.log('第一步:', value);
    return value + 1;
  })
  .then(value => {
    console.log('第二步:', value);
    return value + 1;
  })
  .then(value => {
    console.log('第三步:', value);
  });

// 静态方法测试
MyPromise.all([
  MyPromise.resolve(1),
  new MyPromise(resolve => setTimeout(() => resolve(2), 500)),
  new MyPromise(resolve => setTimeout(() => resolve(3), 1000))
]).then(values => {
  console.log('all方法结果:', values); // [1, 2, 3]
});

总结

通过手写Promise实现,可以深入理解:

  1. Promise的状态机制:三种状态及其不可逆特性
  2. 异步执行原理:使用setTimeout保证回调异步执行
  3. 链式调用实现:then方法返回新Promise
  4. 错误处理机制:统一的catch方法
  5. 静态方法原理:resolve、reject、all、race等