TS分步实现Promise A+规范

参考文章&本文介绍

手把手一行一行代码教你“手写Promise“,完美通过 Promises/A+ 官方872个测试用例手写 Promise - 掘金

这篇文章从Promise A+规范每一条的角度出发,能清晰的看出每段代码与规范对应的地方;

本文主要是从一个简单的demo出发,一步一步有比较的、有使用示例的完善,到最后实现Promise A+规范

分步实现

1.Promise的三种状态、完成值、执行器方法

  • 只实现了 status、resolve/reject、执行器立即执行
  • 能记录 pending/fulfilled/rejected 三种状态
  • 但还不能链式调用和处理回调
// 1. Promise的三种状态、完成值、执行器方法
type Status = 'pending' | 'fulfilled' | 'rejected';
type Executor<T> = (resolve: Resolve<T>, reject: Reject) => void;
type Resolve<T> = (result?: T) => void;
type Reject = (reason?: any) => void;

class MyPromise<T> {
  status: Status = 'pending';
  private fulfilledValue?: T;
  private rejectionReason?: any;

  constructor(executor?: Executor<T>) {
    executor?.(this.resolve, this.reject);
  }

  private resolve: Resolve<T> = (result?: T) => {
    if (this.status !== 'pending') return;

    this.fulfilledValue = result;
    this.status = 'fulfilled';
  };

  private reject: Reject = (reason?: any) => {
    if (this.status !== 'pending') return;

    this.rejectionReason = reason;
    this.status = 'rejected';
  };
}

const p1 = new MyPromise(); // pending

const p2 = new MyPromise((resolve) => {
  resolve();
}); // fulfilled

const p3 = new MyPromise<void>((_, reject) => {
  reject();
}); // rejected

const p4 = new MyPromise<string>((resolve, reject) => {
  setTimeout(() => {
    if (Math.random() > 0.9) {
      resolve('F');
    } else {
      reject('R');
    }
  }, 1000);
}); // pending -> fulfilled or rejected

setTimeout(() => {
  console.log(p1, p2, p3, p4);
}, 1000);

export {};

2.实现then方法的链式调用

  • 引入 then
  • 增加回调队列(pending 时缓存)
  • 开始支持链式调用
  • 还没细致处理回调返回值,也没有微任务。

image-20260106164902982

// 2. 实现then方法的链式调用
type Status = 'pending' | 'fulfilled' | 'rejected';
type Executor<T> = (resolve: Resolve<T>, reject: Reject) => void;
type Resolve<T> = (result?: T) => void;
type Reject = (reason?: any) => void;
type Then<T> = (onFulfilled?: (result?: T) => any, onRejected?: (result?: T) => any) => MyPromise<T>;

class MyPromise<T> {
  status: Status = 'pending';
  private fulfilledValue?: T;
  private rejectionReason?: any;
  private onFulfilledCbList: ((result?: T) => any)[] = [];
  private onRejectedCbList: ((reason?: any) => any)[] = [];

  constructor(executor?: Executor<T>) {
    executor?.(this.resolve, this.reject);
  }

  private resolve: Resolve<T> = (result?: T) => {
    if (this.status !== 'pending') return;

    this.fulfilledValue = result;
    this.status = 'fulfilled';
    this.onFulfilledCbList.forEach((cb) => cb());
  };

  private reject: Reject = (reason?: any) => {
    if (this.status !== 'pending') return;

    this.rejectionReason = reason;
    this.status = 'rejected';
    this.onRejectedCbList.forEach((cb) => cb());
  };

  then: Then<T> = (onFulfilled?: (result?: T) => any, onRejected?: (result?: T) => any) => {
    const promise2 = new MyPromise<T>((resolve, reject) => {
      let hasOnFulfilled = typeof onFulfilled === 'function';
      let hasOnRejected = typeof onRejected === 'function';
      let isFulfilled = this.status === 'fulfilled';
      let isRejected = this.status === 'rejected';
      let isPending = this.status === 'pending';

      if (isPending) {
        // 处理待处理promise的成功回调
        this.onFulfilledCbList.push(() => {
          if (hasOnFulfilled) {
            const x = onFulfilled!(this.fulfilledValue);
            resolve(x); // 此处简化了then的返回值的处理,只处理了返回值为普通值的情况
          } else {
            resolve(this.fulfilledValue); // 如果onFulfilled不是函数,则使用promise2传递调用then的promise
          }
        });
        // 处理待处理promise的失败回调
        this.onRejectedCbList.push(() => {
          if (hasOnRejected) {
            const x = onRejected!(this.rejectionReason);
            resolve(x); // 此处简化了then的返回值的处理,只处理了返回值为普通值的情况
          } else {
            reject(this.rejectionReason); // 如果onRejected不是函数,则使用promise2传递调用then的promise
          }
        });
      } else if (isFulfilled) {
        // 处理已成功promise的回调
        if (hasOnFulfilled) {
          const x = onFulfilled!(this.fulfilledValue);
          resolve(x); // 此处简化了then的返回值的处理,只处理了返回值为普通值的情况
        } else {
          resolve(this.fulfilledValue); // 如果onFulfilled不是函数,则使用promise2传递调用then的promise
        }
      } else if (isRejected) {
        // 处理已失败promise的回调
        if (hasOnRejected) {
          const x = onRejected!(this.rejectionReason);
          resolve(x); // 此处简化了then的返回值的处理,只处理了返回值为普通值的情况
        } else {
          reject(this.rejectionReason); // 如果onRejected不是函数,则使用promise2传递调用then的promise
        }
      }
    });

    return promise2;
  };
}

const p1 = new MyPromise(); // pending

const p2 = new MyPromise((resolve) => {
  resolve();
}); // fulfilled

const p3 = new MyPromise<void>((_, reject) => {
  reject();
}); // rejected

const p4 = new MyPromise<string>((resolve, reject) => {
  setTimeout(() => {
    if (Math.random() > 0.5) {
      resolve('F');
    } else {
      reject('R');
    }
  }, 1000);
}); // pending -> fulfilled or rejected

const p5 = p2
  .then(() => {
    return 1;
  })
  .then(() => {
    return 2;
  }); // 2

const p6 = p4.then(
  (res) => {
    return 'p6-' + res;
  },
  (res) => {
    return 'p6-' + res;
  }
); // 'p6-F' or 'p6-R'

setTimeout(() => {
  console.log(p1, p2, p3, p4, p5, p6);
}, 1000);

export {};

3.入微任务队列

  • 统一把所有 then 回调包装在 queueMicrotask,确保回调总在同步代码之后执行,以模拟原生 Promise 的微任务调度。

image-20260106165033957

// 3. 入微任务队列
type Status = 'pending' | 'fulfilled' | 'rejected';
type Executor<T> = (resolve: Resolve<T>, reject: Reject) => void;
type Resolve<T> = (result?: T) => void;
type Reject = (reason?: any) => void;
type Then<T> = (onFulfilled?: (result?: T) => any, onRejected?: (result?: T) => any) => MyPromise<T>;

class MyPromise<T> {
  status: Status = 'pending';
  private fulfilledValue?: T;
  private rejectionReason?: any;
  private onFulfilledCbList: ((result?: T) => any)[] = [];
  private onRejectedCbList: ((reason?: any) => any)[] = [];

  constructor(executor?: Executor<T>) {
    executor?.(this.resolve, this.reject);
  }

  private resolve: Resolve<T> = (result?: T) => {
    if (this.status !== 'pending') return;

    this.fulfilledValue = result;
    this.status = 'fulfilled';
    this.onFulfilledCbList.forEach((cb) => cb());
  };

  private reject: Reject = (reason?: any) => {
    if (this.status !== 'pending') return;

    this.rejectionReason = reason;
    this.status = 'rejected';
    this.onRejectedCbList.forEach((cb) => cb());
  };

  then: Then<T> = (onFulfilled?: (result?: T) => any, onRejected?: (result?: T) => any) => {
    const promise2 = new MyPromise<T>((resolve, reject) => {
      let hasOnFulfilled = typeof onFulfilled === 'function';
      let hasOnRejected = typeof onRejected === 'function';
      let isFulfilled = this.status === 'fulfilled';
      let isRejected = this.status === 'rejected';
      let isPending = this.status === 'pending';

      if (isPending) {
        // 处理待处理promise的成功回调
        this.onFulfilledCbList.push(() => {
          queueMicrotask(() => {
            if (hasOnFulfilled) {
              const x = onFulfilled!(this.fulfilledValue);
              resolve(x); // 此处简化了then的返回值的处理,只处理了返回值为普通值的情况
            } else {
              resolve(this.fulfilledValue); // 如果onFulfilled不是函数,则使用promise2传递调用then的promise
            }
          });
        });
        // 处理待处理promise的失败回调
        this.onRejectedCbList.push(() => {
          queueMicrotask(() => {
            if (hasOnRejected) {
              const x = onRejected!(this.rejectionReason);
              resolve(x); // 此处简化了then的返回值的处理,只处理了返回值为普通值的情况
            } else {
              reject(this.rejectionReason); // 如果onRejected不是函数,则使用promise2传递调用then的promise
            }
          });
        });
      } else if (isFulfilled) {
        // 处理已成功promise的回调
        queueMicrotask(() => {
          if (hasOnFulfilled) {
            const x = onFulfilled!(this.fulfilledValue);
            resolve(x); // 此处简化了then的返回值的处理,只处理了返回值为普通值的情况
          } else {
            resolve(this.fulfilledValue); // 如果onFulfilled不是函数,则使用promise2传递调用then的promise
          }
        });
      } else if (isRejected) {
        // 处理已失败promise的回调
        queueMicrotask(() => {
          if (hasOnRejected) {
            const x = onRejected!(this.rejectionReason);
            resolve(x); // 此处简化了then的返回值的处理,只处理了返回值为普通值的情况
          } else {
            reject(this.rejectionReason); // 如果onRejected不是函数,则使用promise2传递调用then的promise
          }
        });
      }
    });

    return promise2;
  };
}

const p1 = new MyPromise(); // pending

const p2 = new MyPromise((resolve) => {
  resolve();
}); // fulfilled

const p3 = new MyPromise<void>((_, reject) => {
  reject();
}); // rejected

const p4 = new MyPromise<string>((resolve, reject) => {
  setTimeout(() => {
    if (Math.random() > 0.5) {
      resolve('F');
    } else {
      reject('R');
    }
  }, 1000);
}); // pending -> fulfilled or rejected

const p5 = p2
  .then(() => {
    return 1;
  })
  .then(() => {
    return 2;
  }); // 2

const p6 = p4.then(
  (res) => {
    return 'p6-' + res;
  },
  (res) => {
    return 'p6-' + res;
  }
); // 'p6-F' or 'p6-R'

new MyPromise<string>((resolve) => resolve('micro')).then((val) => {
  console.log('then 回调(应在微任务阶段执行)', val);
});
console.log('同步日志(应先输出)');

setTimeout(() => {
  console.log(p1, p2, p3, p4, p5, p6);
}, 1000);

export {};

4.实现根据onFulfilled、onRejected的返回值,处理then方法返回的Promise。实现状态吸收

  • 引入 resolvePromise2 处理 then 回调的返回值(普通值、Promise、不包括 thenable对象)
  • 实现状态吸收(链式调用能正确转化嵌套 promise)
  • 解决循环引用问题。

image-20260106165125216

// 4. 实现根据onFulfilled、onRejected的返回值,处理then方法返回的Promise。实现状态吸收
type Status = 'pending' | 'fulfilled' | 'rejected';
type Executor<T> = (resolve: Resolve<T>, reject: Reject) => void;
type Resolve<T> = (result?: T) => void;
type Reject = (reason?: any) => void;
type Then<T> = (onFulfilled?: (result?: T) => any, onRejected?: (result?: T) => any) => MyPromise<T>;

class MyPromise<T> {
  status: Status = 'pending';
  private fulfilledValue?: T;
  private rejectionReason?: any;
  private onFulfilledCbList: ((result?: T) => any)[] = [];
  private onRejectedCbList: ((reason?: any) => any)[] = [];

  constructor(executor?: Executor<T>) {
    executor?.(this.resolve, this.reject);
  }

  private resolve: Resolve<T> = (result?: T) => {
    if (this.status !== 'pending') return;

    this.fulfilledValue = result;
    this.status = 'fulfilled';
    this.onFulfilledCbList.forEach((cb) => cb());
  };

  private reject: Reject = (reason?: any) => {
    if (this.status !== 'pending') return;

    this.rejectionReason = reason;
    this.status = 'rejected';
    this.onRejectedCbList.forEach((cb) => cb());
  };

  then: Then<T> = (onFulfilled?: (result?: T) => any, onRejected?: (result?: T) => any) => {
    const promise2 = new MyPromise<T>((resolve, reject) => {
      let hasOnFulfilled = typeof onFulfilled === 'function';
      let hasOnRejected = typeof onRejected === 'function';
      let isFulfilled = this.status === 'fulfilled';
      let isRejected = this.status === 'rejected';
      let isPending = this.status === 'pending';

      if (isPending) {
        // 处理待处理promise的成功回调
        this.onFulfilledCbList.push(() => {
          queueMicrotask(() => {
            if (hasOnFulfilled) {
              const x = onFulfilled!(this.fulfilledValue as T);
              resolvePromise2(promise2, resolve, reject, x);
            } else {
              resolve(this.fulfilledValue as T); // 如果onFulfilled不是函数,则使用promise2传递调用then的promise
            }
          });
        });
        // 处理待处理promise的失败回调
        this.onRejectedCbList.push(() => {
          queueMicrotask(() => {
            if (hasOnRejected) {
              const x = onRejected!(this.rejectionReason);
              resolvePromise2(promise2, resolve, reject, x);
            } else {
              reject(this.rejectionReason); // 如果onRejected不是函数,则使用promise2传递调用then的promise
            }
          });
        });
      } else if (isFulfilled) {
        // 处理已成功promise的回调
        queueMicrotask(() => {
          if (hasOnFulfilled) {
            const x = onFulfilled!(this.fulfilledValue as T);
            resolvePromise2(promise2, resolve, reject, x);
          } else {
            resolve(this.fulfilledValue as T); // 如果onFulfilled不是函数,则使用promise2传递调用then的promise
          }
        });
      } else if (isRejected) {
        // 处理已失败promise的回调
        queueMicrotask(() => {
          if (hasOnRejected) {
            const x = onRejected!(this.rejectionReason);
            resolvePromise2(promise2, resolve, reject, x);
          } else {
            reject(this.rejectionReason); // 如果onRejected不是函数,则使用promise2传递调用then的promise
          }
        });
      }
    });

    return promise2;
  };
}

function resolvePromise2<T>(promise2: MyPromise<T>, resolve: Resolve<T>, reject: Reject, x: any): void {
  if (promise2 === x) {
    /**
     * 防止这种情况出现
     * const p2 = new MyPromise((resolve) => resolve()).then(() => p2);
     */
    throw new TypeError('Chaining cycle detected for promise');
  }

  if (x instanceof MyPromise) {
    // Promise对象
    x.then((y) => resolvePromise2(promise2, resolve, reject, y), reject); // 如果内层Promise是成功状态,则继续递归
  } else if (x && isThisType(x.then, 'Function')) {
    // thenable对象
    x.then((y: any) => resolvePromise2(promise2, resolve, reject, y), reject); // 此处简化了对thenable对象的处理,只处理了用户调用一次resolve或者reject的情况
  } else {
    // 普通值
    resolve(x);
  }
}

function isThisType(x: any, type: string): boolean {
  return Object.prototype.toString.call(x) === `[object ${type}]`;
}

const p1 = new MyPromise(); // pending

const p2 = new MyPromise((resolve) => {
  resolve();
}); // fulfilled

const p3 = new MyPromise<void>((_, reject) => {
  reject();
}); // rejected

const p4 = new MyPromise<string>((resolve, reject) => {
  setTimeout(() => {
    if (Math.random() > 0.5) {
      resolve('F');
    } else {
      reject('R');
    }
  }, 1000);
}); // pending -> fulfilled or rejected

const p5 = p2
  .then(() => {
    return 1;
  })
  .then(() => {
    return 2;
  }); // 2

const p6 = p4.then(
  (res) => {
    return 'p6-' + res;
  },
  (res) => {
    return 'p6-' + res;
  }
); // 'p6-F' or 'p6-R'

new MyPromise<string>((resolve) => resolve('micro')).then((val) => {
  console.log('then 回调(应在微任务阶段执行)', val);
});
console.log('同步日志(应先输出)');

const p7 = p2.then(() => new MyPromise((resolve) => resolve('inner promise'))); // inner promise

setTimeout(() => {
  console.log(p1, p2, p3, p4, p5, p6, p7);
}, 1000);

export {};

5.添加错误处理、对于thenable对象的特殊处理

  • 添加异常处理
  • 添加thenable处理:
    • thenable 的 then 读取和执行都要安全且只能 settle 一次(示例演示 tricky thenable 的行为)

image-20260106165307257

// 5. 添加错误处理、对于thenable对象的特殊处理
type Status = 'pending' | 'fulfilled' | 'rejected';
type Executor<T> = (resolve: Resolve<T>, reject: Reject) => void;
type Resolve<T> = (result?: T | Thenable<T>) => void;
type Reject = (reason?: any) => void;
type Then<T> = (onFulfilled?: (result?: T) => any, onRejected?: (result?: T) => any) => MyPromise<T>;
type Thenable<T> = {
  then(resolve: Resolve<T>, reject: Reject): void;
};

class MyPromise<T> {
  status: Status = 'pending';
  private fulfilledValue?: T | Thenable<T>;
  private rejectionReason?: any;
  private onFulfilledCbList: ((result?: T) => any)[] = [];
  private onRejectedCbList: ((reason?: any) => any)[] = [];

  constructor(executor?: Executor<T>) {
    try {
      executor?.(this.resolve, this.reject);
    } catch (error) {
      this.reject(error as any);
    }
  }

  private resolve: Resolve<T> = (result?: T | Thenable<T>) => {
    if (this.status !== 'pending') return;

    this.fulfilledValue = result;
    this.status = 'fulfilled';
    this.onFulfilledCbList.forEach((cb) => cb());
  };

  private reject: Reject = (reason?: any) => {
    if (this.status !== 'pending') return;

    this.rejectionReason = reason;
    this.status = 'rejected';
    this.onRejectedCbList.forEach((cb) => cb());
  };

  then: Then<T> = (onFulfilled?: (result?: T) => any, onRejected?: (result?: T) => any) => {
    const promise2 = new MyPromise<T>((resolve, reject) => {
      let hasOnFulfilled = typeof onFulfilled === 'function';
      let hasOnRejected = typeof onRejected === 'function';
      let isFulfilled = this.status === 'fulfilled';
      let isRejected = this.status === 'rejected';
      let isPending = this.status === 'pending';

      if (isPending) {
        // 处理待处理promise的成功回调
        this.onFulfilledCbList.push(() => {
          queueMicrotask(() => {
            try {
              if (hasOnFulfilled) {
                const x = onFulfilled!(this.fulfilledValue as T);
                resolvePromise2(promise2, resolve, reject, x);
              } else {
                resolve(this.fulfilledValue as T); // 如果onFulfilled不是函数,则使用promise2传递调用then的promise
              }
            } catch (error) {
              reject(error);
            }
          });
        });
        // 处理待处理promise的失败回调
        this.onRejectedCbList.push(() => {
          queueMicrotask(() => {
            try {
              if (hasOnRejected) {
                const x = onRejected!(this.rejectionReason);
                resolvePromise2(promise2, resolve, reject, x);
              } else {
                reject(this.rejectionReason); // 如果onRejected不是函数,则使用promise2传递调用then的promise
              }
            } catch (error) {
              reject(error);
            }
          });
        });
      } else if (isFulfilled) {
        // 处理已成功promise的回调
        queueMicrotask(() => {
          try {
            if (hasOnFulfilled) {
              const x = onFulfilled!(this.fulfilledValue as T);
              resolvePromise2(promise2, resolve, reject, x);
            } else {
              resolve(this.fulfilledValue as T); // 如果onFulfilled不是函数,则使用promise2传递调用then的promise
            }
          } catch (error) {
            reject(error);
          }
        });
      } else if (isRejected) {
        // 处理已失败promise的回调
        queueMicrotask(() => {
          try {
            if (hasOnRejected) {
              const x = onRejected!(this.rejectionReason);
              resolvePromise2(promise2, resolve, reject, x);
            } else {
              reject(this.rejectionReason); // 如果onRejected不是函数,则使用promise2传递调用then的promise
            }
          } catch (error) {
            reject(error);
          }
        });
      }
    });

    return promise2;
  }
}

function resolvePromise2<T>(promise2: MyPromise<T>, resolve: Resolve<T>, reject: Reject, x: any): void {
  if (promise2 === x) {
    /**
     * 防止这种情况出现
     * const p2 = new MyPromise((resolve) => resolve()).then(() => p2);
     */
    throw new TypeError('Chaining cycle detected for promise');
  }

  if (x instanceof MyPromise) {
    // Promise对象
    x.then((y) => resolvePromise2(promise2, resolve, reject, y), reject); // 如果内层Promise是成功状态,则继续递归
  } else if (isThisType(x, 'Function') || isThisType(x, 'Object')) {
    let then: any = null;
    try {
      then = x.then;
    } catch (error) {
      reject(error);
    }
    if (isThisType(then, 'Function')) {
      // thenable对象
      let called = false;
      try {
        then!.call(
          x,
          (y: any) => {
            if (called) return;
            called = true;
            resolvePromise2(promise2, resolve, reject, y); // 如果内层Promise是成功状态,则继续递归
          }, // resolvePromise
          (z: any) => {
            if (called) return;
            called = true;
            reject(z);
          } // rejectPromise
        );
      } catch (error) {
        if (called) return;
        called = true;
        reject(error);
      }
    } else {
      resolve(x);
    }
  } else {
    // 普通值
    resolve(x);
  }
}

function isThisType(x: any, type: string): boolean {
  return Object.prototype.toString.call(x) === `[object ${type}]`;
}

const p1 = new MyPromise(); // pending

const p2 = new MyPromise((resolve) => {
  resolve();
}); // fulfilled

const p3 = new MyPromise<void>((_, reject) => {
  reject();
}); // rejected

const p4 = new MyPromise<string>((resolve, reject) => {
  setTimeout(() => {
    if (Math.random() > 0.5) {
      resolve('F');
    } else {
      reject('R');
    }
  }, 1000);
}); // pending -> fulfilled or rejected

const p5 = p2
  .then(() => {
    return 1;
  })
  .then(() => {
    return 2;
  }); // 2

const p6 = p4.then(
  (res) => {
    return 'p6-' + res;
  },
  (res) => {
    return 'p6-' + res;
  }
); // 'p6-F' or 'p6-R'

new MyPromise<string>((resolve) => resolve('micro')).then((val) => {
  console.log('then 回调(应在微任务阶段执行)', val);
});
console.log('同步日志(应先输出)');

const p7 = p2.then(() => new MyPromise((resolve) => resolve('inner promise'))); // inner promise

/**
 * trickyThenable 演示:
 * 1. 首先 resolve 一个“仍在等待的 thenable”(里面用 setTimeout 异步再 resolve 真值)
 * 2. 紧接着同步调用 reject
 *
 * - 启用 called:同步 reject 被忽略,等异步 resolve 后输出「最终结果: 最终成功」
 * - 注释 called:promise 仍处于 pending,因此同步 reject 会生效,输出「最终结果: 后来又失败」
 *
 * 为什么myPromise不需要做这种限制?
 * 因为对于Thenable对象,resolve或者reject的调用是由用户自己决定的,而myPromise中,是由myPromise类中的resolvePromise2决定的
 */
const pendingThenable: Thenable<string> = {
  then(innerResolve) {
    if (!innerResolve) return;
    setTimeout(() => innerResolve('成功'), 0);
  },
};
const trickyThenable: Thenable<string> = {
  then(resolve: any, reject: any) {
    // 先resolve了这个Thenable对象
    resolve(pendingThenable as any);
    // 后reject了这个Thenable对象(根据规范,应该忽略reject的调用)
    reject('失败');
  },
};
new MyPromise((resolve) => resolve('占位值'))
  .then(() => trickyThenable)
  .then(
    (res) => console.log('最终结果:', res),
    (err) => console.error('最终结果:', err)
  );

setTimeout(() => {
  console.log(p1, p2, p3, p4, p5, p6, p7);
}, 1000);

export {};

6.优化类型

image-20260106165408558

// 6. 优化类型
type Status = 'pending' | 'fulfilled' | 'rejected';
type Executor<T> = (resolve: Resolve<T>, reject: Reject) => void;
type Resolve<T> = (result?: T | Thenable<T>) => void;
type Reject = (reason?: any) => void;
type Thenable<T> = {
  then<TResult1 = T, TResult2 = never>(
    onFulfilled?: ((result: T) => TResult1 | Thenable<TResult1>) | undefined | null,
    onRejected?: ((reason: any) => TResult2 | Thenable<TResult2>) | undefined | null
  ): any;
};

class MyPromise<T> {
  status: Status = 'pending';
  private fulfilledValue?: T | Thenable<T>;
  private rejectionReason?: any;
  private onFulfilledCbList: ((result?: T) => any)[] = [];
  private onRejectedCbList: ((reason?: any) => any)[] = [];

  constructor(executor?: Executor<T>) {
    try {
      executor?.(this.resolve, this.reject);
    } catch (error) {
      this.reject(error as any);
    }
  }

  private resolve: Resolve<T> = (result?: T | Thenable<T>) => {
    if (this.status !== 'pending') return;

    this.fulfilledValue = result;
    this.status = 'fulfilled';
    this.onFulfilledCbList.forEach((cb) => cb());
  };

  private reject: Reject = (reason?: any) => {
    if (this.status !== 'pending') return;

    this.rejectionReason = reason;
    this.status = 'rejected';
    this.onRejectedCbList.forEach((cb) => cb());
  };

  then<TResult1 = T, TResult2 = never>(
    onFulfilled?: ((result: T) => TResult1 | Thenable<TResult1>) | undefined | null,
    onRejected?: ((result: any) => TResult2 | Thenable<TResult2>) | undefined | null
  ): MyPromise<TResult1 | TResult2> {
    const promise2 = new MyPromise<TResult1 | TResult2>((resolve, reject) => {
      let hasOnFulfilled = typeof onFulfilled === 'function';
      let hasOnRejected = typeof onRejected === 'function';
      let isFulfilled = this.status === 'fulfilled';
      let isRejected = this.status === 'rejected';
      let isPending = this.status === 'pending';

      if (isPending) {
        // 处理待处理promise的成功回调
        this.onFulfilledCbList.push(() => {
          queueMicrotask(() => {
            try {
              if (hasOnFulfilled) {
                const x = onFulfilled!(this.fulfilledValue as T);
                resolvePromise2(promise2, resolve, reject, x);
              } else {
                resolve(this.fulfilledValue as TResult1 | TResult2 | Thenable<TResult1 | TResult2> | undefined); // 如果onFulfilled不是函数,则使用promise2传递调用then的promise
              }
            } catch (error) {
              reject(error);
            }
          });
        });
        // 处理待处理promise的失败回调
        this.onRejectedCbList.push(() => {
          queueMicrotask(() => {
            try {
              if (hasOnRejected) {
                const x = onRejected!(this.rejectionReason);
                resolvePromise2(promise2, resolve, reject, x);
              } else {
                reject(this.rejectionReason); // 如果onRejected不是函数,则使用promise2传递调用then的promise
              }
            } catch (error) {
              reject(error);
            }
          });
        });
      } else if (isFulfilled) {
        // 处理已成功promise的回调
        queueMicrotask(() => {
          try {
            if (hasOnFulfilled) {
              const x = onFulfilled!(this.fulfilledValue as T);
              resolvePromise2(promise2, resolve, reject, x);
            } else {
              resolve(this.fulfilledValue as TResult1 | TResult2 | Thenable<TResult1 | TResult2> | undefined); // 如果onFulfilled不是函数,则使用promise2传递调用then的promise
            }
          } catch (error) {
            reject(error);
          }
        });
      } else if (isRejected) {
        // 处理已失败promise的回调
        queueMicrotask(() => {
          try {
            if (hasOnRejected) {
              const x = onRejected!(this.rejectionReason);
              resolvePromise2(promise2, resolve, reject, x);
            } else {
              reject(this.rejectionReason); // 如果onRejected不是函数,则使用promise2传递调用then的promise
            }
          } catch (error) {
            reject(error);
          }
        });
      }
    });

    return promise2;
  }
}

function resolvePromise2<T>(promise2: MyPromise<T>, resolve: Resolve<T>, reject: Reject, x: any): void {
  if (promise2 === x) {
    /**
     * 防止这种情况出现
     * const p2 = new MyPromise((resolve) => resolve()).then(() => p2);
     */
    throw new TypeError('Chaining cycle detected for promise');
  }

  if (x instanceof MyPromise) {
    // Promise对象
    x.then((y) => resolvePromise2(promise2, resolve, reject, y), reject); // 如果内层Promise是成功状态,则继续递归
  } else if (isThisType(x, 'Function') || isThisType(x, 'Object')) {
    let then: any = null;
    try {
      then = x.then;
    } catch (error) {
      reject(error);
    }
    if (isThisType(then, 'Function')) {
      // thenable对象
      let called = false;
      try {
        then!.call(
          x,
          (y: any) => {
            if (called) return;
            called = true;
            resolvePromise2(promise2, resolve, reject, y); // 如果内层Promise是成功状态,则继续递归
          }, // resolvePromise
          (z: any) => {
            if (called) return;
            called = true;
            reject(z);
          } // rejectPromise
        );
      } catch (error) {
        if (called) return;
        called = true;
        reject(error);
      }
    } else {
      resolve(x);
    }
  } else {
    // 普通值
    resolve(x);
  }
}

function isThisType(x: any, type: string): boolean {
  return Object.prototype.toString.call(x) === `[object ${type}]`;
}

const p1 = new MyPromise(); // pending

const p2 = new MyPromise((resolve) => {
  resolve();
}); // fulfilled

const p3 = new MyPromise<void>((_, reject) => {
  reject();
}); // rejected

const p4 = new MyPromise<string>((resolve, reject) => {
  setTimeout(() => {
    if (Math.random() > 0.5) {
      resolve('F');
    } else {
      reject('R');
    }
  }, 1000);
}); // pending -> fulfilled or rejected

const p5 = p2
  .then(() => {
    return 1;
  })
  .then(() => {
    return 2;
  }); // 2

const p6 = p4.then(
  (res) => {
    return 'p6-' + res;
  },
  (res) => {
    return 'p6-' + res;
  }
); // 'p6-F' or 'p6-R'

new MyPromise<string>((resolve) => resolve('micro')).then((val) => {
  console.log('then 回调(应在微任务阶段执行)', val);
});
console.log('同步日志(应先输出)');

const p7 = p2.then(() => new MyPromise((resolve) => resolve('inner promise'))); // inner promise

/**
 * trickyThenable 演示:
 * 1. 首先 resolve 一个“仍在等待的 thenable”(里面用 setTimeout 异步再 resolve 真值)
 * 2. 紧接着同步调用 reject
 *
 * - 启用 called:同步 reject 被忽略,等异步 resolve 后输出「最终结果: 最终成功」
 * - 注释 called:promise 仍处于 pending,因此同步 reject 会生效,输出「最终结果: 后来又失败」
 *
 * 为什么myPromise不需要做这种限制?
 * 因为对于Thenable对象,resolve或者reject的调用是由用户自己决定的,而myPromise中,是由myPromise类中的resolvePromise2决定的
 */
const pendingThenable: Thenable<string> = {
  then(innerResolve) {
    if (!innerResolve) return;
    setTimeout(() => innerResolve('成功'), 0);
  },
};
const trickyThenable: Thenable<string> = {
  then(resolve: any, reject: any) {
    // 先resolve了这个Thenable对象
    resolve(pendingThenable as any);
    // 后reject了这个Thenable对象(根据规范,应该忽略reject的调用)
    reject('失败');
  },
};
new MyPromise((resolve) => resolve('占位值'))
  .then(() => trickyThenable)
  .then(
    (res) => console.log('最终结果:', res),
    (err) => console.error('最终结果:', err)
  );

setTimeout(() => {
  console.log(p1, p2, p3, p4, p5, p6, p7);
}, 1000);

export {};

测试

  1. 安装promises-aplus-tests

  2. 将编译之后的js代码放在index.js中

    // index.js
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    var MyPromise = /** @class */ (function () {
        // ...
    }());
    function resolvePromise2(promise2, resolve, reject, x) {
        // ...
    }
    function isThisType(x, type) {
        // ...
    }
    
  3. 添加deferred静态方法

    // index.js
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    var MyPromise = /** @class */ (function () {
        // ...
    }());
    function resolvePromise2(promise2, resolve, reject, x) {
        // ...
    }
    function isThisType(x, type) {
        // ...
    }
    
    MyPromise.deferred = function() {
      let result = {};
      result.promise = new MyPromise((resolve, reject) => {
        result.resolve = resolve;
        result.reject = reject;
      });
      return result;
    }
    
    module.exports = MyPromise;
    
  4. 修改package.json

    {
      "dependencies": {
        "promises-aplus-tests": "^2.1.2"
      },
      "scripts": {
        "test": "promises-aplus-tests index"
      }
    }
    
  5. 执行命令

    pnpm test
    
posted @ 2026-01-06 17:00  CatCatcher  阅读(16)  评论(0)    收藏  举报
#