手写promise

0 阅读6分钟

纯JavaScript手写Promise实现,包含详细注释和完整功能。

/**
 * 手写Promise实现(符合Promise/A+规范)
 * 包含完整注释,展示Promise内部工作原理
 */

// 定义Promise的三种状态常量
const PENDING = 'pending';      // 等待状态
const FULFILLED = 'fulfilled';  // 成功状态
const REJECTED = 'rejected';    // 失败状态

/**
 * 手写Promise类
 */
class MyPromise {
  /**
   * 构造函数:接收一个执行器函数
   * @param {Function} executor - 立即执行的函数,接收resolve和reject两个参数
   */
  constructor(executor) {
    // 初始化状态为pending
    this.status = PENDING;
    
    // 成功后的值(默认undefined)
    this.value = undefined;
    
    // 失败后的原因(默认undefined)
    this.reason = undefined;
    
    // 存储成功回调函数(支持多个then调用)
    this.onFulfilledCallbacks = [];
    
    // 存储失败回调函数
    this.onRejectedCallbacks = [];

    // 使用箭头函数绑定this,保证resolve和reject中的this指向当前Promise实例
    const resolve = (value) => {
      // 只有pending状态才能转换为fulfilled或rejected
      if (this.status === PENDING) {
        // 状态变为fulfilled
        this.status = FULFILLED;
        // 保存成功的值
        this.value = value;
        
        // 执行所有成功回调(异步执行,符合微任务特性)
        this.onFulfilledCallbacks.forEach(callback => {
          callback();
        });
      }
    };

    const reject = (reason) => {
      // 只有pending状态才能转换
      if (this.status === PENDING) {
        // 状态变为rejected
        this.status = REJECTED;
        // 保存失败的原因
        this.reason = reason;
        
        // 执行所有失败回调
        this.onRejectedCallbacks.forEach(callback => {
          callback();
        });
      }
    };

    try {
      // 立即执行executor
      executor(resolve, reject);
    } catch (error) {
      // 如果执行器抛出异常,直接reject
      reject(error);
    }
  }

  /**
   * then方法:注册成功和失败的回调
   * @param {Function} onFulfilled - 成功回调
   * @param {Function} onRejected - 失败回调
   * @returns {MyPromise} 返回新的Promise,支持链式调用
   */
  then(onFulfilled, onRejected) {
    // 参数可选:如果不是函数,则忽略(值穿透)
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
    onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason; };

    // 创建并返回一个新的Promise
    const promise2 = new MyPromise((resolve, reject) => {
      // 根据当前状态执行不同的逻辑
      if (this.status === FULFILLED) {
        // 使用setTimeout模拟微任务(实际Promise是微任务,这里用宏任务简化)
        setTimeout(() => {
          try {
            // 执行成功回调
            const x = onFulfilled(this.value);
            // 处理回调返回值
            this.resolvePromise(promise2, x, resolve, reject);
          } catch (error) {
            reject(error);
          }
        }, 0);
      } else if (this.status === REJECTED) {
        setTimeout(() => {
          try {
            const x = onRejected(this.reason);
            this.resolvePromise(promise2, x, resolve, reject);
          } catch (error) {
            reject(error);
          }
        }, 0);
      } else {
        // 状态为pending:将回调保存起来,等待状态改变后再执行
        this.onFulfilledCallbacks.push(() => {
          setTimeout(() => {
            try {
              const x = onFulfilled(this.value);
              this.resolvePromise(promise2, x, resolve, reject);
            } catch (error) {
              reject(error);
            }
          }, 0);
        });

        this.onRejectedCallbacks.push(() => {
          setTimeout(() => {
            try {
              const x = onRejected(this.reason);
              this.resolvePromise(promise2, x, resolve, reject);
            } catch (error) {
              reject(error);
            }
          }, 0);
        });
      }
    });

    return promise2;
  }

  /**
   * 处理then回调返回值的核心方法
   * @param {MyPromise} promise2 - 当前then返回的新Promise
   * @param {*} x - 上一个then回调的返回值
   * @param {Function} resolve - promise2的resolve
   * @param {Function} reject - promise2的reject
   */
  resolvePromise(promise2, x, resolve, reject) {
    // 防止循环引用:如果x和promise2相同,则抛出错误
    if (promise2 === x) {
      return reject(new TypeError('Chaining cycle detected for promise'));
    }

    // 标记是否已经调用过,防止多次调用
    let called = false;

    // 如果x是MyPromise实例
    if (x instanceof MyPromise) {
      // 执行x,根据x的状态决定promise2的状态
      x.then(
        y => {
          // 递归解析,直到x不是Promise为止
          this.resolvePromise(promise2, y, resolve, reject);
        },
        r => {
          reject(r);
        }
      );
    } 
    // 如果x是对象或函数
    else if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
      try {
        // 获取then方法(兼容第三方Promise)
        const then = x.then;
        
        if (typeof then === 'function') {
          // 如果then是函数,说明x是一个thenable对象
          then.call(
            x,
            y => {
              if (called) return;
              called = true;
              // 递归解析
              this.resolvePromise(promise2, y, resolve, reject);
            },
            r => {
              if (called) return;
              called = true;
              reject(r);
            }
          );
        } else {
          // 普通对象,直接resolve
          resolve(x);
        }
      } catch (error) {
        if (called) return;
        called = true;
        reject(error);
      }
    } else {
      // 基础类型值,直接resolve
      resolve(x);
    }
  }

  /**
   * catch方法:只处理失败情况
   * @param {Function} onRejected 
   * @returns {MyPromise}
   */
  catch(onRejected) {
    return this.then(null, onRejected);
  }

  /**
   * finally方法:无论成功失败都会执行
   * @param {Function} callback 
   * @returns {MyPromise}
   */
  finally(callback) {
    return this.then(
      value => MyPromise.resolve(callback()).then(() => value),
      reason => MyPromise.resolve(callback()).then(() => { throw reason; })
    );
  }

  /**
   * 静态resolve方法
   * @param {*} value 
   * @returns {MyPromise}
   */
  static resolve(value) {
    // 如果value已经是MyPromise实例,直接返回
    if (value instanceof MyPromise) {
      return value;
    }
    // 否则返回一个新的成功状态的Promise
    return new MyPromise(resolve => resolve(value));
  }

  /**
   * 静态reject方法
   * @param {*} reason 
   * @returns {MyPromise}
   */
  static reject(reason) {
    return new MyPromise((resolve, reject) => reject(reason));
  }

  /**
   * 静态all方法:所有成功才成功,一个失败就失败
   * @param {Array} promises 
   * @returns {MyPromise}
   */
  static all(promises) {
    return new MyPromise((resolve, reject) => {
      const results = [];
      let count = 0;
      const total = promises.length;

      // 处理空数组
      if (total === 0) {
        resolve(results);
        return;
      }

      promises.forEach((promise, index) => {
        // 确保每个项都是Promise
        MyPromise.resolve(promise).then(
          value => {
            results[index] = value;
            count++;
            // 所有都成功才resolve
            if (count === total) {
              resolve(results);
            }
          },
          reason => {
            // 任何一个失败直接reject
            reject(reason);
          }
        );
      });
    });
  }

  /**
   * 静态race方法:谁先改变状态就采用谁的结果
   * @param {Array} promises 
   * @returns {MyPromise}
   */
  static race(promises) {
    return new MyPromise((resolve, reject) => {
      promises.forEach(promise => {
        MyPromise.resolve(promise).then(resolve, reject);
      });
    });
  }

  /**
   * 静态allSettled:等待所有Promise完成,返回所有结果
   * @param {Array} promises 
   * @returns {MyPromise}
   */
  static allSettled(promises) {
    return new MyPromise(resolve => {
      const results = [];
      let count = 0;
      const total = promises.length;

      if (total === 0) {
        resolve(results);
        return;
      }

      promises.forEach((promise, index) => {
        MyPromise.resolve(promise).then(
          value => {
            results[index] = { status: 'fulfilled', value };
            count++;
            if (count === total) resolve(results);
          },
          reason => {
            results[index] = { status: 'rejected', reason };
            count++;
            if (count === total) resolve(results);
          }
        );
      });
    });
  }

  /**
   * 静态any:只要有一个成功就成功,全部失败才失败
   * @param {Array} promises 
   * @returns {MyPromise}
   */
  static any(promises) {
    return new MyPromise((resolve, reject) => {
      const errors = [];
      let count = 0;
      const total = promises.length;

      if (total === 0) {
        reject(new AggregateError('All promises were rejected'));
        return;
      }

      promises.forEach((promise, index) => {
        MyPromise.resolve(promise).then(
          value => {
            resolve(value);
          },
          reason => {
            errors[index] = reason;
            count++;
            if (count === total) {
              reject(new AggregateError(errors, 'All promises were rejected'));
            }
          }
        );
      });
    });
  }
}

// ------------------- 测试代码 -------------------

console.log('========== 手写Promise测试 ==========\n');

// 测试1:基础功能
console.log('测试1:基础功能');
const p1 = new MyPromise((resolve, reject) => {
  console.log('执行器立即执行');
  setTimeout(() => {
    resolve('成功啦!');
    // reject('失败啦!');
  }, 1000);
});

p1.then(
  value => {
    console.log('成功回调:', value);
  },
  reason => {
    console.log('失败回调:', reason);
  }
);

// 测试2:链式调用
console.log('\n测试2:链式调用');
const p2 = new MyPromise(resolve => {
  resolve(1);
});

p2.then(value => {
  console.log('then1:', value);
  return value + 1;
}).then(value => {
  console.log('then2:', value);
  return value + 1;
}).then(value => {
  console.log('then3:', value);
});

// 测试3:静态resolve/reject
console.log('\n测试3:静态方法');
MyPromise.resolve('直接成功').then(console.log);
MyPromise.reject('直接失败').catch(console.log);

// 测试4:all方法
console.log('\n测试4:Promise.all');
const promises = [
  MyPromise.resolve(1),
  MyPromise.resolve(2),
  new MyPromise(resolve => setTimeout(() => resolve(3), 100))
];

MyPromise.all(promises).then(
  results => console.log('all结果:', results),
  error => console.log('all错误:', error)
);

// 测试5:race方法
console.log('\n测试5:Promise.race');
const racePromises = [
  new MyPromise(resolve => setTimeout(() => resolve('慢的'), 200)),
  new MyPromise(resolve => setTimeout(() => resolve('快的'), 100)),
  new MyPromise((resolve, reject) => setTimeout(() => reject('错误'), 50))
];

MyPromise.race(racePromises).then(
  value => console.log('race胜出:', value),
  reason => console.log('race失败:', reason)
);

// 测试6:allSettled
console.log('\n测试6:Promise.allSettled');
const mixedPromises = [
  MyPromise.resolve(1),
  MyPromise.reject('错误信息'),
  new MyPromise(resolve => setTimeout(() => resolve(3), 50))
];

MyPromise.allSettled(mixedPromises).then(results => {
  console.log('allSettled结果:', results);
});

// 测试7:any方法
console.log('\n测试7:Promise.any');
const anyPromises = [
  MyPromise.reject('错误1'),
  MyPromise.reject('错误2'),
  MyPromise.resolve('成功!')
];

MyPromise.any(anyPromises).then(
  value => console.log('any成功:', value),
  error => console.log('any失败:', error)
);

// 测试8:catch和finally
console.log('\n测试8:catch和finally');
new MyPromise((resolve, reject) => {
  reject('出错了');
})
  .then(value => {
    console.log('不会执行');
  })
  .catch(reason => {
    console.log('catch捕获:', reason);
    return '从错误中恢复';
  })
  .then(value => {
    console.log('catch后的then:', value);
  })
  .finally(() => {
    console.log('finally执行');
  });

// 测试9:值穿透
console.log('\n测试9:值穿透');
MyPromise.resolve(42)
  .then()
  .then()
  .then(value => {
    console.log('值穿透结果:', value);
  });

// 测试10:异常捕获
console.log('\n测试10:异常捕获');
new MyPromise(() => {
  throw new Error('执行器内错误');
}).catch(error => {
  console.log('捕获到执行器错误:', error.message);
});

// 测试11:then中抛出错误
MyPromise.resolve(10)
  .then(value => {
    console.log('then中值:', value);
    throw new Error('then中抛出的错误');
  })
  .catch(error => {
    console.log('捕获到then中错误:', error.message);
  });

// 测试12:循环引用检测
console.log('\n测试12:循环引用检测');
const promiseA = new MyPromise(resolve => {
  resolve(1);
});

const promiseB = promiseA.then(() => {
  return promiseB; // 返回自身,应该报错
});

promiseB.catch(error => {
  console.log('捕获到循环引用错误:', error.message);
});

// 测试13:多个then调用
console.log('\n测试13:多个then调用');
const p3 = new MyPromise(resolve => {
  setTimeout(() => resolve('数据'), 100);
});

p3.then(value => console.log('then A:', value));
p3.then(value => console.log('then B:', value));
p3.then(value => console.log('then C:', value));

console.log('\n========== 测试完成 ==========');

这个手写Promise实现包含了:

📚 核心功能

  • 三种状态管理:pending/fulfilled/rejected
  • then方法:支持链式调用和值穿透
  • catch方法:错误处理
  • finally方法:无论成功失败都会执行

🔧 静态方法

  • resolve:返回成功状态的Promise
  • reject:返回失败状态的Promise
  • all:所有成功才成功,一个失败即失败
  • race:竞速,返回第一个改变状态的Promise
  • allSettled:等待所有完成,返回所有结果
  • any:一个成功即成功,全部失败才失败

⚙️ 内部机制

  • 状态不可逆:pending -> fulfilled/rejected,不可逆转
  • 回调存储:支持多个then同时注册
  • 值穿透:then中可以传非函数参数
  • 循环引用检测:防止then返回自身
  • thenable处理:兼容其他Promise库
  • 异步执行:使用setTimeout模拟微任务