AI 生成的摘要
本文详细讲述了如何实现一个符合 Promise A+ 规范的 JavaScript Promise 类。从基础原理入手,文章逐步介绍了 Promise 的基本结构和功能,包括创建 Promise 实例和实现状态转换,以及解决异步调用问题。文章通过定义并实现一系列的逻辑步骤,解决了 Promise 的状态管理、结果存储、错误处理等问题。核心过程包括 resolve 和 reject 方法的绑定、异常捕获、以及 then 方法的链式调用支持。特别地,文章深入探讨了 Promise 的解决过程,并通过实现 resolvePromise 函数来保证 Promise 链的正确性和循环引用的处理。此外,文章还采用 promises-aplus-tests 进行测试,验证实现的正确性。读者通过本文可以获得创建一个功能完整且符合规范的 Promise 类的详尽指导,深入理解 JavaScript 异步处理的精髓。

简单实现

首先,实现这个最简单的使用方式

ts
new Promise((resolve, reject) => {
  resolve(1)
})

分析一下,Promise 实例接受一个 Function,Function 接受两个参数,分别为 resolve,reject 实现:

ts
type Fn = (resole: (value: any) => void, reject: (reason: any) => void) => void

class Promise2025 {
  constructor(fn: Fn) {
    fn(this._resolve, this._reject)
  }

  _resolve(value: any) {
  }

  _reject(reason: any) {
  }
}

然后,开始为 promise 增加状态,promise 有三种状态,分别是pendingfulfilledrejected,初始状态为 pending,pending 可以转为 fulfilled(resolve) 和 rejected(reject),状态不可逆转,fulfilled 和 rejected 也不可以互相转。 定义状态枚举:

ts
type Fn = (resole: (value: any) => void, reject: (reason: any) => void) => void

enum Status {
  PENDING = 'pending',
  FULFILLED = 'fulfilled',
  REJECTED = 'rejected'
}

class Promise2025 {
  constructor(fn: Fn) {
    // 默认为 pending
    this.promiseState = Status.PENDING
    fn(this._resolve, this._reject)
  }

  promiseState: Status

  _resolve(value: any) {
    // resolve 后,如果为 pending 就变为 fulfilled,不为 pending 就不变(不可逆转)
    if (this.promiseState === Status.PENDING) {
      this.promiseState = Status.FULFILLED
    }
  }

  _reject(reason: any) {
    // reject 后,如果为 pending 就变为 rejected,不为 pending 就不变(不可逆转)
    if (this.promiseState === Status.PENDING) {
      this.promiseState = Status.REJECTED
    }
  }
}

接下来是存储执行结果,promise 中使用promiseResult来存储 resolve 和 reject 的结果,我们只需要在执行 resolve 和 reject 时存一下就OK:

ts
promiseResult: any
  
_resolve(value: any) {
  // resolve 后,如果为 pending 就变为 fulfilled,不为 pending 就不变(不可逆转)
  if (this.promiseState === Status.PENDING) {
    this.promiseState = Status.FULFILLED
    this.promiseResult = value
  }
}

_reject(reason: any) {
  // reject 后,如果为 pending 就变为 rejected,不为 pending 就不变(不可逆转)
  if (this.promiseState === Status.PENDING) {
    this.promiseState = Status.REJECTED
    this.promiseResult = reason
  }
}

这时候应该发现有些不对了,复习一下关于 this 指向的八股文

JSthis指向取决于环境。 全局环境中的this,直接指向全局对象。 函数环境中的this,取决于函数如何被调用:

  1. 如果函数是直接调用的,同时又是出于严格模式下,则指向undefined,如果不是严格模式,则指向全局对象
  2. 如果函数是通过一个对象调用的,则指向对象本身
  3. 如果函数是通过一些特殊方法调用的,比如callapplybind,通过这些方法调用的话,则指向指定的对象
  4. 如果函数是通过new调用的,则指向新的实例。 另外,箭头函数由于没有this,所以箭头函数内部的this由其外部作用域决定。
我们的\_resolve 与\_reject 中,是直接调用的,那么我们在函数内部中直接使用`this.xxx`其实是我们 class 中的 this 的,所以我们需要使用 bind 来给他指定一下 this。
ts
constructor(fn: Fn) {
    // 默认为 pending
    this.promiseState = Status.PENDING
    // 使用 bind 绑定 this
    fn(this._resolve.bind(this), this._reject.bind(this))
  }

这里修改完了后,还需要考虑一个问题,如果我们的 fn 执行报错了怎么办? 在 promise 中,如果 fn 执行报错,那么也是直接触发 reject,我们可以在 fn 执行时使用 try catch 来捕获异常,放到 _reject 中

ts
constructor(fn: Fn) {
    // 默认为 pending
    this.promiseState = Status.PENDING
    try {
      fn(this._resolve.bind(this), this._reject.bind(this))
    } catch (error) {
      this._reject(error)
    }
  }

then的简单实现

接下来就到了 then的实现,依旧是一个简单的示例

ts
new Promise((resolve, reject) => {
  resolve(1)
}).then((res) => {}, (reason) => {})

分析一下,这里的 then 接收两个参数,第一个是 resolve 时触发的回调,第二个是 reject 触发的回调。很轻松就可以做到这一点。

ts
class Promise2025 {
  constructor(fn: Fn) {
    // 默认为 pending
    this.promiseState = Status.PENDING
    try {
      fn(this._resolve.bind(this), this._reject.bind(this))
    } catch (error) {
      this._reject(error)
    }
  }

  promiseState: Status
  promiseResult: any

  _resolve(value: any) {
    // resolve 后,如果为 pending 就变为 fulfilled,不为 pending 就不变(不可逆转)
    if (this.promiseState === Status.PENDING) {
      this.promiseState = Status.FULFILLED
      this.promiseResult = value
    }
  }

  _reject(reason: any) {
    // reject 后,如果为 pending 就变为 rejected,不为 pending 就不变(不可逆转)
    if (this.promiseState === Status.PENDING) {
      this.promiseState = Status.REJECTED
      this.promiseResult = reason
    }
  }

  // ++++++++++++++++++++++++++++++++++++++++++++++++
  then(onFulfilled: (value: any) => void, onRejected: (reason: any) => void) {
    if (this.promiseState === Status.FULFILLED) {
      onFulfilled(this.promiseResult)
    }
    if (this.promiseState === Status.REJECTED) {
      onRejected(this.promiseResult)
    }
  }
}

测试一下目前的功能:

ts
promise1.then((res) => {
  console.log(res)
}, (reason) => {
  console.log(reason)
})

const promise2 = new Promise2025((resolve, reject) => {
  reject(2)
})

promise2.then((res) => {
  console.log(res)
}, (reason) => {
  console.log(reason)
})

const promise3 = new Promise2025((resolve, reject) => {
  throw new Error('error')
})

promise3.then((res) => {
  console.log(res)
}, (reason) => {
  console.log(reason)
})

接下来开始实现异步功能,具体就是把then的执行时机放到下一次微任务队列。我们使用queueMicrotask来实现。

ts
then(onFulfilled: (value: any) => void, onRejected: (reason: any) => void) {
   if (this.promiseState === Status.FULFILLED) {
     queueMicrotask(() => {
       onFulfilled(this.promiseResult)
     })
   }
   if (this.promiseState === Status.REJECTED) {
     queueMicrotask(() => {
       onRejected(this.promiseResult)
     })
   }
 }

测试: 可以看到,第二种情况下,then 并没有正常调用。我们在我们的 promise 中打印一下每个阶段的状态:

ts
type Fn = (resole: (value: any) => void, reject: (reason: any) => void) => void

enum Status {
  PENDING = 'pending',
  FULFILLED = 'fulfilled',
  REJECTED = 'rejected'
}

class Promise2025 {
  constructor(fn: Fn) {
    // 默认为 pending
    this.promiseState = Status.PENDING
    try {
      fn(this._resolve.bind(this), this._reject.bind(this))
    } catch (error) {
      this._reject(error)
    }
  }

  promiseState: Status
  promiseResult: any

  _resolve(value: any) {
    console.log('----------执行 resolve----------');
    
    // resolve 后,如果为 pending 就变为 fulfilled,不为 pending 就不变(不可逆转)
    if (this.promiseState === Status.PENDING) {
      this.promiseState = Status.FULFILLED
      this.promiseResult = value
    }
  }

  _reject(reason: any) {
    console.log('----------执行 reject----------');
    
    // reject 后,如果为 pending 就变为 rejected,不为 pending 就不变(不可逆转)
    if (this.promiseState === Status.PENDING) {
      this.promiseState = Status.REJECTED
      this.promiseResult = reason
    }
  }

  then(onFulfilled: (value: any) => void, onRejected: (reason: any) => void) {
    console.log('----------执行 then----------');
    if (this.promiseState === Status.FULFILLED) {
      queueMicrotask(() => {
        onFulfilled(this.promiseResult)
      })
    }
    if (this.promiseState === Status.REJECTED) {
      queueMicrotask(() => {
        onRejected(this.promiseResult)
      })
    }
  }
}

console.log('1')
 new Promise2025((resolve, reject) => {
  setTimeout(() => {
    console.log('--------------fn 执行----------')
    resolve('3')
  }, 0)
}).then(res => {
  console.log(res)
}, err => {})
console.log('4')

查看输出 执行时机明显不对,我们的 then 在 fn 之前就开始执行了,此时还没有执行 resolve,promise 的状态还是 pending,所以在 then 什么都不会做。原理也很简单,settimeout 是宏任务,宏任务会在下一个队列才执行。那么我们可以在 then调用时判断 promise 的状态,如果状态为 pending,那么先把回调存起来,等到 resolve 或 reject 调用时再触发。

ts
type Fn = (resole: (value: any) => void, reject: (reason: any) => void) => void

enum Status {
  PENDING = 'pending',
  FULFILLED = 'fulfilled',
  REJECTED = 'rejected'
}

class Promise2025 {
  constructor(fn: Fn) {
    // 设置默认
    this.promiseState = Status.PENDING
    this.promiseResult = null
    // +++++++++++++++++++++++++++++
    this.onFulfilled = []
    this.onRejected = []
    try {
      fn(this._resolve.bind(this), this._reject.bind(this))
    } catch (error) {
      this._reject(error)
    }
  }

  promiseState: Status
  promiseResult: any
  // ++++++++++++++++++++++
  onFulfilled: Array<(value: any) => void> = []
  onRejected: Array<(reason: any) => void> = []

  _resolve(value: any) {
    // resolve 后,如果为 pending 就变为 fulfilled,不为 pending 就不变(不可逆转)
    if (this.promiseState === Status.PENDING) {
      this.promiseState = Status.FULFILLED
      this.promiseResult = value
      // ++++++++++++++++++++++++++++++
      queueMicrotask(() => {
        this.onFulfilled.forEach(fn => fn(value))
      })
    }
  }

  _reject(reason: any) {
    // reject 后,如果为 pending 就变为 rejected,不为 pending 就不变(不可逆转)
    if (this.promiseState === Status.PENDING) {
      this.promiseState = Status.REJECTED
      this.promiseResult = reason
      // ++++++++++++++++++++++++++++++
      queueMicrotask(() => {
        this.onRejected.forEach(fn => fn(reason))
      })
    }
  }

  then(onFulfilled: (value: any) => void, onRejected: (reason: any) => void) {
  // +++++++++++++++++++++++++++++++++++
    if (this.promiseState === Status.PENDING) {
      this.onFulfilled.push(onFulfilled)
      this.onRejected.push(onRejected)
    }
    if (this.promiseState === Status.FULFILLED) {
      queueMicrotask(() => {
        onFulfilled(this.promiseResult)
      })
    }
    if (this.promiseState === Status.REJECTED) {
      queueMicrotask(() => {
        onRejected(this.promiseResult)
      })
    }
  }
}

再测试一下: 这下就正常了。为什么onFulfilled是数组呢?因为这样可以支持 then 的多次调用,比如 测试一下我们的 promise: 然后来给 then 中的 resolve 和 reject 改为可选参数,如果reject 不为 function 的话且执行到的话,就抛出异常,如果 resolve 不为 function且执行的话,就返回 value。

ts
then(onFulfilled?: (value: any) => void, onRejected?: (reason: any) => void) {
 // +++++++++++++++++++
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
    // ++++++++++++++++++++
    onRejected = typeof onRejected === 'function' ? onRejected : reason => {
        throw reason;
    };
    if (this.promiseState === Status.PENDING) {
      this.onFulfilled.push(onFulfilled)
      this.onRejected.push(onRejected)
    }
    if (this.promiseState === Status.FULFILLED) {
      queueMicrotask(() => {
        onFulfilled(this.promiseResult)
      })
    }
    if (this.promiseState === Status.REJECTED) {
      queueMicrotask(() => {
        onRejected(this.promiseResult)
      })
    }

then的链式调用

接下来要实现的是 then 的链式调用,这是手写 promise 最麻烦的部分。

ts
let p1 = new Promise<number>((resolve, reject) => {
    resolve(100)
})
p1.then(res => {
    console.log('fulfilled', res);
    return 2 * res
}).then(res => {
    console.log('fulfilled', res)
})

// 输出 fulfilled 100 fulfilled 200
const p2 = new Promise<number>((resolve, reject) => {
    resolve(100)
})

p2.then(res => {
    console.log('fulfilled', res);
    return new Promise((resolve, reject) => resolve(3 * res))
}).then(res => {
    console.log('fulfilled', res)
})
// 输出 fulfilled 100 fulfilled 300

这块就要根据 Promise A+规范来了。 这里简单复制过来。

2.2.7then 必须返回一个 Promise。 2.2.7.1如果 onFulfilled 或 onRejected 返回值 x,运行 Promise 解决程序 Resolve(promise2, x)。 2.2.7.2如果 onFulfilled 或 onRejected 抛出异常 e,promise2 必须以 e 为原因被拒绝。\ 2.2.7.3如果 onFulfilled 不是一个函数且 promise1 被满足,promise2 必须以与 promise1 相同的值被满足。\ 2.2.7.4如果 onRejected 不是一个函数且 promise1 被拒绝,promise2 必须以与 promise1 相同的原因被拒绝。 2.3Promise 解决过程\ Promise 解决过程是一个抽象操作,输入一个 Promise 和一个值,我们将其表示为 Resolve(promise, x)。如果 x 是一个 thenable,它尝试让 promise 采纳 x 的状态,假设 x 至少表现得像是一个 Promise。否则,它用值 x 满足 promise。 这种对 thenables 的处理允许 Promise 实现进行互操作,只要它们暴露一个符合 Promises/A+ 的 then 方法。它也允许 Promises/A+ 实现能够同化具有合理 then 方法的非符合实现。 要运行 Resolve(promise, x),执行以下步骤: 2.3.1如果 promise 和 x 指向同一个对象,则以 TypeError 为原因拒绝 promise。\ 2.3.2如果 x 是一个 Promise,则采用其状态:\ 2.3.2.1如果 x 处于挂起状态,promise 必须保持挂起,直到 x 被兑现或拒绝。\ 2.3.2.2如果或当 x 被兑现时,以相同的值兑现 promise。\ 2.3.2.3如果或当 x 被拒绝时,用同样的原因拒绝 promise。 2.3.3否则,如果 x 是一个对象或函数,\ 2.3.3.1让 then 成为 x.then。\ 2.3.3.2如果检索属性 x.then 导致抛出异常 e,则以 e 为理由拒绝 promise。\ 2.3.3.3如果 then 是一个函数,使用 x 作为 this,第一个参数为 resolvePromise,第二个参数为 rejectPromise,其中:\ 2.3.3.3.1如果或当 resolvePromise 被用值 y 调用时,运行 Resolve(promise, y)。\ 2.3.3.3.2如果或当 rejectPromise 被调用并传入理由 r 时,使用 r 拒绝 promise。\ 2.3.3.3.3如果 resolvePromise 和 rejectPromise 都被调用,或者对同一个参数进行了多次调用,则第一次调用具有优先级,后续的调用将被忽略。\ 2.3.3.3.4如果调用 then 抛出异常 e,\ 2.3.3.3.4.1如果 resolvePromise 或 rejectPromise 已经被调用,则忽略它。\ 2.3.3.3.4.2否则,使用 e 作为原因拒绝 promise。 2.3.3.4如果 then 不是一个函数,则用 x 满足 promise。\ 2.3.4如果 x 不是一个对象或函数,则用 x 满足 promise。 如果一个 Promise 使用了一个参与循环 thenable 链的 thenable 来解析,以至于 Resolve(promise, thenable) 的递归性质最终导致 Resolve(promise, thenable) 被再次调用,按照上述算法会导致无限递归。鼓励但不是必须要求实现检测这种递归,并以一个信息量丰富的 TypeError 作为理由来拒绝 promise。

这里借用一下大佬的总结:

  1. then方法本身会返回一个新的Promise对象,返回一个新的Promise以后它就有自己的then方法,这样就能实现无限的链式。
  2. 不论 promise1 被 resolve() 还是被 reject() 时 promise2 都会执行 Promise 解决过程:Resolve(promise2, x)

先来实现then方法中返回一个新 promise

ts
then(onFulfilled?: (value: T) => void, onRejected?: (reason: any) => void): any {
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
    onRejected = typeof onRejected === 'function' ? onRejected : reason => {
        throw reason;
    };

    const promise = new Promise2025<T>(async (resolve, reject) => { 
      if (this.promiseState === Status.PENDING) {
        this.onFulfilled.push(onFulfilled)
        this.onRejected.push(onRejected)
      }
      if (this.promiseState === Status.FULFILLED) {
        queueMicrotask(() => {
          onFulfilled(this.promiseResult)
        })
      }
      if (this.promiseState === Status.REJECTED) {
        queueMicrotask(() => {
          onRejected(this.promiseResult)
        })
      }
    });

    return promise
  }

实现不论 promise1 被 resolve() 还是被 reject() 时 promise2 都会执行 Promise 解决过程。

ts
// promise 的解决过程
function resolvePromise(promise2, x, resolve, reject) {}
....
....
then(onFulfilled?: (value: T) => void, onRejected?: (reason: any) => void): any {
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
    onRejected = typeof onRejected === 'function' ? onRejected : reason => {
        throw reason;
    };

    const promise = new Promise2025<T>(async (resolve, reject) => { 
      if (this.promiseState === Status.PENDING) {
        this.onFulfilled.push(onFulfilled)
        this.onRejected.push(onRejected)
      }
      if (this.promiseState === Status.FULFILLED) {
        queueMicrotask(() => {
          const x = onFulfilled(this.promiseResult)
          // ++++++++++++++++++++
          resolvePromise(promise, x, resolve, reject)
        })
      }
      if (this.promiseState === Status.REJECTED) {
        queueMicrotask(() => {
          const x = onRejected(this.promiseResult)
          // ++++++++++++++++++++
          resolvePromise(promise, x, resolve, reject)
        })
      }
    });

    return promise
  }

这里 promise的解决过程放到resolvePromise中,后续再实现。 实现如果如果 onFulfilled 或 onRejected 抛出异常 e,promise2 必须以 e 为原因被拒绝。

ts
then(onFulfilled?: (value: T) => void, onRejected?: (reason: any) => void): any {
  onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
  onRejected = typeof onRejected === 'function' ? onRejected : reason => {
      throw reason;
  };

  const promise = new Promise2025<T>(async (resolve, reject) => { 
    if (this.promiseState === Status.PENDING) {
      this.onFulfilled.push(onFulfilled)
      this.onRejected.push(onRejected)
    }
    if (this.promiseState === Status.FULFILLED) {
      queueMicrotask(() => {
      // +++++++++++++++++++++++++++
        try {
          const x = onFulfilled(this.promiseResult)
          resolvePromise(promise, x, resolve, reject)
        } catch (e) {
          reject(e)
        }
      })
    }
    if (this.promiseState === Status.REJECTED) {
      queueMicrotask(() => {
      // +++++++++++++++++++++++++++++
        try {
          const x = onRejected(this.promiseResult)
          resolvePromise(promise, x, resolve, reject)
        } catch (e) {
          reject(e)
        }
      })
    }
  });

  return promise
}

注意这里的 reject 是 promise2(也就是return 的 promise 的 reject)。 同时修改 pending 状态中的处理。

ts
class Promise2025<T> {
  constructor(fn: Fn) {
    // 设置默认
    this.promiseState = Status.PENDING
    this.promiseResult = null
    this.onFulfilled = []
    this.onRejected = []
    try {
      fn(this._resolve.bind(this), this._reject.bind(this))
    } catch (error) {
      this._reject(error)
    }
  }

  promiseState: Status
  promiseResult: any
  onFulfilled: Array<(value: T) => void> = []
  onRejected: Array<(reason: any) => void> = []

  _resolve(value: T) {
    // resolve 后,如果为 pending 就变为 fulfilled,不为 pending 就不变(不可逆转)
    if (this.promiseState === Status.PENDING) {
      this.promiseState = Status.FULFILLED
      this.promiseResult = value
      // +++++++++++++++++++++++++
      // queueMicrotask(() => {
        this.onFulfilled.forEach(fn => fn(value))
      // })
    }
  }

  _reject(reason: any) {
    // reject 后,如果为 pending 就变为 rejected,不为 pending 就不变(不可逆转)
    if (this.promiseState === Status.PENDING) {
      this.promiseState = Status.REJECTED
      this.promiseResult = reason
      // +++++++++++++++++++++++++
      // queueMicrotask(() => {
        this.onRejected.forEach(fn => fn(reason))
      // })
    }
  }

  then(onFulfilled?: (value: T) => void, onRejected?: (reason: any) => void): any {
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
    onRejected = typeof onRejected === 'function' ? onRejected : reason => {
        throw reason;
    };

    const promise = new Promise2025<T>(async (resolve, reject) => { 
      if (this.promiseState === Status.PENDING) {
        this.onFulfilled.push(() => {
      // +++++++++++++++++++++++++
          queueMicrotask(() => {
            try {
              const x = onFulfilled(this.promiseResult)
              resolvePromise(promise, x, resolve, reject)
            } catch (e) {
              reject(e)
            }
          })
        })
        this.onRejected.push(() => {
      // +++++++++++++++++++++++++
          queueMicrotask(() => {
            try {
              const x = onRejected(this.promiseResult)
              resolvePromise(promise, x, resolve, reject)
            } catch (e) {
              reject(e)
            }
          })
        })
      }
      if (this.promiseState === Status.FULFILLED) {
        queueMicrotask(() => {
          try {
            const x = onFulfilled(this.promiseResult)
            resolvePromise(promise, x, resolve, reject)
          } catch (e) {
            reject(e)
          }
        })
      }
      if (this.promiseState === Status.REJECTED) {
        queueMicrotask(() => {
          try {
            const x = onRejected(this.promiseResult)
            resolvePromise(promise, x, resolve, reject)
          } catch (e) {
            reject(e)
          }
        })
      }
    });

    return promise
  }
}

如果 onFulfilled 不是一个函数且 promise1 被满足, promise2 必须以与 promise1 相同的值被满足

ts
then(onFulfilled?: (value: T) => void, onRejected?: (reason: any) => void): any {
    // -------------------
    const promise = new Promise2025<T>(async (resolve, reject) => { 
      if (this.promiseState === Status.PENDING) {
        this.onFulfilled.push(() => {
          queueMicrotask(() => {
            try {
            // +++++++++++++++
              if (typeof onFulfilled !== 'function') {
                resolve(this.promiseResult)
              } else {
                const x = onFulfilled(this.promiseResult)
                resolvePromise(promise, x, resolve, reject)
              }
            } catch (e) {
              reject(e)
            }
          })
        })
        this.onRejected.push(() => {
          queueMicrotask(() => {
            try {
              const x = onRejected(this.promiseResult)
              resolvePromise(promise, x, resolve, reject)
            } catch (e) {
              reject(e)
            }
          })
        })
      }
      if (this.promiseState === Status.FULFILLED) {
        queueMicrotask(() => {
        // +++++++++++++++++
          try {
            if (typeof onFulfilled !== 'function') {
              resolve(this.promiseResult)
            } else {
              const x = onFulfilled(this.promiseResult)
              resolvePromise(promise, x, resolve, reject)
            }
          } catch (e) {
            reject(e)
          }
        })
      }
      if (this.promiseState === Status.REJECTED) {
        queueMicrotask(() => {
          try {
            const x = onRejected(this.promiseResult)
            resolvePromise(promise, x, resolve, reject)
          } catch (e) {
            reject(e)
          }
        })
      }
    });

    return promise
  }

如果 onRejected 不是一个函数且 promise1 被拒绝, promise2 必须以与 promise1 相同的原因被拒绝。

ts
then(onFulfilled?: (value: T) => void, onRejected?: (reason: any) => void): any {
    const promise = new Promise2025<T>(async (resolve, reject) => { 
      if (this.promiseState === Status.PENDING) {
        this.onFulfilled.push(() => {
          queueMicrotask(() => {
            try {
              if (typeof onFulfilled !== 'function') {
                resolve(this.promiseResult)
              } else {
                const x = onFulfilled(this.promiseResult)
                resolvePromise(promise, x, resolve, reject)
              }
            } catch (e) {
              reject(e)
            }
          })
        })
        this.onRejected.push(() => {
          queueMicrotask(() => {
            try {
            // +++++++++++++++++++++
              if (typeof onRejected !== 'function') {
                reject(this.promiseResult)
              } else {
                const x = onRejected(this.promiseResult)
                resolvePromise(promise, x, resolve, reject)
              }
            } catch (e) {
              reject(e)
            }
          })
        })
      }
      if (this.promiseState === Status.FULFILLED) {
        queueMicrotask(() => {
          try {
            if (typeof onFulfilled !== 'function') {
              resolve(this.promiseResult)
            } else {
              const x = onFulfilled(this.promiseResult)
              resolvePromise(promise, x, resolve, reject)
            }
          } catch (e) {
            reject(e)
          }
        })
      }
      if (this.promiseState === Status.REJECTED) {
        queueMicrotask(() => {
          try {
          // ++++++++++++++++
            if (typeof onRejected !== 'function') {
              reject(this.promiseResult)
            } else {
              const x = onRejected(this.promiseResult)
              resolvePromise(promise, x, resolve, reject)
            }
          } catch (e) {
            reject(e)
          }
        })
      }
    });

    return promise
  }

根据A+规范 2.3,实现 resolvePromise 2.3.1 如果 promise 和 x 指向同一个对象,则以 TypeError 为原因拒绝 promise

ts
function resolvePromise(promise2, x, resolve, reject) {
  if (promise2 === x) {
    return reject(new TypeError('循环引用'))
  }
}

2.3.2 如果 x 是一个 Promise,则采用其状态。如果 x 处于挂起状态, promise 必须保持挂起,直到 x 被兑现或拒绝。如果/当 x 被兑现时,以相同的值兑现 promise 。如果/当 x 被拒绝时,用同样的原因拒绝 promise 。

ts
function resolvePromise(promise2, x, resolve, reject) {
  if (promise2 === x) {
    return reject(new TypeError('循环引用'))
  }
  if (x instanceof Promise2025) {
    x.then(y => {
      resolvePromise(promise2, y, resolve, reject)
    }, reject)
  }
}

2.3.3 如果 x 是一个对象或函数。让 then 成为 x.then,如果检索属性 x.then 导致抛出异常 e ,则以 e 为理由拒绝 promise

ts
function resolvePromise(promise2, x, resolve, reject) {
  if (promise2 === x) {
    return reject(new TypeError('循环引用'))
  }
  if (x instanceof Promise2025) {
    x.then(y => {
      resolvePromise(promise2, y, resolve, reject)
    }, reject)
  } else if (x !== null && (typeof x === 'object' || typeof x === 'function')) { 
  // ++++++++++++++++++++++++++
    let then
    try {
      then = x.then
    } catch (e) {
      reject(e)
    }
  }
}

如果 then 是一个函数,使用 x 作为 this ,第一个参数为 resolvePromise ,第二个参数为 rejectPromise

ts
function resolvePromise(promise2, x, resolve, reject) {
  if (promise2 === x) {
    return reject(new TypeError('循环引用'))
  }
  if (x instanceof Promise2025) {
    x.then(y => {
      resolvePromise(promise2, y, resolve, reject)
    }, reject)
  } else if (x !== null && (typeof x === 'object' || typeof x === 'function')) { 
    let then
    try {
      then = x.then
    } catch (e) {
      reject(e)
    }
    // ++++++++++++++++++++
    if (typeof then === 'function') { 
      then.call(x, y => {
        // 如果/当 `resolvePromise` 被用值 `y` 调用时,运行 `[[Resolve]](promise, y)` 。
        resolvePromise(promise2, y, resolve, reject)
        //如果/当 `rejectPromise` 被调用并传入理由 `r` 时,使用 `r` 拒绝 `promise` 。
      }, reject)
    }
  }
}

如果 resolvePromise 和 rejectPromise 都被调用,或者对同一个参数进行了多次调用,则第一次调用具有优先级,后续的调用将被忽略。

ts
function resolvePromise(promise2, x, resolve, reject) {
  if (promise2 === x) {
    return reject(new TypeError('循环引用'))
  }
  if (x instanceof Promise2025) {
    x.then(y => {
      resolvePromise(promise2, y, resolve, reject)
    }, reject)
  } else if (x !== null && (typeof x === 'object' || typeof x === 'function')) { 
    let then
    try {
      then = x.then
    } catch (e) {
      reject(e)
    }
    if (typeof then === 'function') { 
    // ++++++++++++++++++++++
      let called = false
      then.call(x, y => {
        if (called) return
        called = true
        resolvePromise(promise2, y, resolve, reject)
      }, r => {
        if (called) return
        called = true
        reject(r)
      })
    }
  }
}

如果调用 then 抛出异常 e,如果 resolvePromise 或 rejectPromise 已经被调用,则忽略它,否则,使用 e 作为原因拒绝 promise 。

ts
function resolvePromise(promise2, x, resolve, reject) {
  if (promise2 === x) {
    return reject(new TypeError('循环引用'))
  }
  if (x instanceof Promise2025) {
    x.then(y => {
      resolvePromise(promise2, y, resolve, reject)
    }, reject)
  } else if (x !== null && (typeof x === 'object' || typeof x === 'function')) { 
    let then
    try {
      then = x.then
    } catch (e) {
      reject(e)
    }
    if (typeof then === 'function') { 
      let called = false
      try {
        then.call(x, y => {
          if (called) return
          called = true
          resolvePromise(promise2, y, resolve, reject)
        }, r => {
          if (called) return
          called = true
          reject(r)
        })
      } catch (e) {
      // ++++++++++++++++++++++++++++++
        // 如果 `resolvePromise` 或 `rejectPromise` 已经被调用,则忽略它
        if (called) return
        //否则,使用 `e` 作为原因拒绝 `promise` 。
        reject(e)
      }
    }
  }
}

如果 then 不是一个函数,则用 x 满足 promise,如果 x 不是一个对象或函数,则用 x 满足 promise 。

ts
function resolvePromise(promise2, x, resolve, reject) {
  if (promise2 === x) {
    return reject(new TypeError('循环引用'))
  }
  if (x instanceof Promise2025) {
    x.then(y => {
      resolvePromise(promise2, y, resolve, reject)
    }, reject)
  } else if (x !== null && (typeof x === 'object' || typeof x === 'function')) { 
    let then
    try {
      then = x.then
    } catch (e) {
      reject(e)
    }
    if (typeof then === 'function') { 
      let called = false
      try {
        then.call(x, y => {
          if (called) return
          called = true
          resolvePromise(promise2, y, resolve, reject)
        }, r => {
          if (called) return
          called = true
          reject(r)
        })
      } catch (e) {
        // 如果 `resolvePromise` 或 `rejectPromise` 已经被调用,则忽略它
        if (called) return
        //否则,使用 `e` 作为原因拒绝 `promise` 。
        reject(e)
      }
    } else {
      // 如果 `then` 不是一个函数,则用 `x` 满足 `promise`
      resolve(x)
    }
  } else {
    // 如果 x 不是一个对象或函数,则用 x 满足 promise 。
    resolve(x)
  }
}

结束

这样 promise 就完成了,使用 promises-aplus-tests工具测试: 最后完善一下类型。

ts
type Fn = (resole: (value: any) => void, reject: (reason: any) => void) => void

enum Status {
  PENDING = 'pending',
  FULFILLED = 'fulfilled',
  REJECTED = 'rejected'
}

type Resolve<T> = (value: T | PromiseLike<T>) => void
type Reject = (reason?: any) => void;

class Promise2025<T> {
  constructor(fn: Fn) {
    // 设置默认
    this.promiseState = Status.PENDING
    this.onFulfilled = []
    this.onRejected = []
    try {
      fn(this._resolve.bind(this), this._reject.bind(this))
    } catch (error) {
      this._reject(error)
    }
  }

  promiseState: Status
  promiseResult: T
  onFulfilled: Resolve<T>[] = []
  onRejected: Reject[] = []

  _resolve(value: T) {
    // resolve 后,如果为 pending 就变为 fulfilled,不为 pending 就不变(不可逆转)
    if (this.promiseState === Status.PENDING) {
      this.promiseState = Status.FULFILLED
      this.promiseResult = value
        this.onFulfilled.forEach(fn => fn(value))
    }
  }

  _reject(reason: any) {
    // reject 后,如果为 pending 就变为 rejected,不为 pending 就不变(不可逆转)
    if (this.promiseState === Status.PENDING) {
      this.promiseState = Status.REJECTED
      this.promiseResult = reason
      // queueMicrotask(() => {
        this.onRejected.forEach(fn => fn(reason))
      // })
    }
  }

  then(onFulfilled?: (value: T) => T | PromiseLike<T>, onRejected?: (reason: any) => any): any {
    const promise = new Promise2025<T>(async (resolve, reject) => { 
      if (this.promiseState === Status.PENDING) {
        this.onFulfilled.push(() => {
          queueMicrotask(() => {
            try {
              if (typeof onFulfilled !== 'function') {
                resolve(this.promiseResult)
              } else {
                const x = onFulfilled(this.promiseResult)
                resolvePromise(promise, x, resolve, reject)
              }
            } catch (e) {
              reject(e)
            }
          })
        })
        this.onRejected.push(() => {
          queueMicrotask(() => {
            try {
              if (typeof onRejected !== 'function') {
                reject(this.promiseResult)
              } else {
                const x = onRejected(this.promiseResult)
                resolvePromise(promise, x, resolve, reject)
              }
            } catch (e) {
              reject(e)
            }
          })
        })
      }
      if (this.promiseState === Status.FULFILLED) {
        queueMicrotask(() => {
          try {
            if (typeof onFulfilled !== 'function') {
              resolve(this.promiseResult)
            } else {
              const x = onFulfilled(this.promiseResult)
              resolvePromise(promise, x, resolve, reject)
            }
          } catch (e) {
            reject(e)
          }
        })
      }
      if (this.promiseState === Status.REJECTED) {
        queueMicrotask(() => {
          try {
            if (typeof onRejected !== 'function') {
              reject(this.promiseResult)
            } else {
              const x = onRejected(this.promiseResult)
              resolvePromise(promise, x, resolve, reject)
            }
          } catch (e) {
            reject(e)
          }
        })
      }
    });

    return promise
  }
}

// promise 的解决过程
function resolvePromise<T>(promise2: Promise2025<T>, x: T | PromiseLike<T>, resolve: Resolve<T>, reject: Reject) {
  if (promise2 === x) {
    return reject(new TypeError('循环引用'))
  }
  if (x instanceof Promise2025) {
    x.then(y => {
      resolvePromise(promise2, y, resolve, reject)
    }, reject)
  } else if (x !== null && (typeof x === 'object' || typeof x === 'function')) { 
    let then: PromiseLike<T>['then'] | undefined = undefined
    try {
      then = (x as PromiseLike<T>).then
    } catch (e) {
      reject(e)
    }
    if (typeof then === 'function') { 
      let called = false
      try {
        then.call(x, ((y: T | PromiseLike<T>) => {
          if (called) return
          called = true
          resolvePromise(promise2, y, resolve, reject)
        }), ((r: any) => {
          if (called) return
          called = true
          reject(r)
        }))
      } catch (e) {
        // 如果 `resolvePromise` 或 `rejectPromise` 已经被调用,则忽略它
        if (called) return
        //否则,使用 `e` 作为原因拒绝 `promise` 。
        reject(e)
      }
    } else {
      // 如果 `then` 不是一个函数,则用 `x` 满足 `promise`
      resolve(x)
    }
  } else {
    // 如果 x 不是一个对象或函数,则用 x 满足 promise 。
    resolve(x)
  }
}

module.exports = Promise2025

promise的其他方法

promise.all

Promise.all() 静态方法接受一个 Promise 可迭代对象作为输入,并返回一个 Promise。当所有输入的 Promise 都被兑现时,返回的 Promise 也将被兑现(即使传入的是一个空的可迭代对象),并返回一个包含所有兑现值的数组。如果输入的任何 Promise 被拒绝,则返回的 Promise 将被拒绝,并带有第一个被拒绝的原因。

ts
function isPromise(value: any): value is PromiseLike<any> {
  return value instanceof Promise2025 || (typeof value === 'object' && value !== null && typeof value.then === 'function')
}

all(promises: PromiseLike<any>[]) {
    return new Promise((resolve, reject) => {
      if (promises.length === 0) {
        resolve([]);
        return;
      }

      const results = new Array(promises.length);
      let count = 0;

      promises.forEach((p, i) => {
        Promise.resolve(p)
          .then(value => {
            results[i] = value;
            count++;
            if (count === promises.length) {
              resolve(results);
            }
          })
          .catch(reject); // 有一个失败就直接 reject
      });
    });
  }

promise.any

Promise.any() 静态方法将一个 Promise 可迭代对象作为输入,并返回一个 Promise。当输入的任何一个 Promise 兑现时,这个返回的 Promise 将会兑现,并返回第一个兑现的值。当所有输入 Promise 都被拒绝(包括传递了空的可迭代对象)时,它会以一个包含拒绝原因数组的 AggregateError 拒绝。

ts
any(promises: PromiseLike<any>[]) {
    return new Promise((resolve, reject) => {
      if (promises.length === 0) {
        reject(new AggregateError([], 'All promises were rejected'));
        return;
      }

      let count = 0;
      const errors = new Array(promises.length);

      promises.forEach((p, i) => {
        Promise.resolve(p)
          .then(resolve)
          .catch(err => {
            errors[i] = err;
            count++;
            if (count === promises.length) {
              reject(new AggregateError(errors, 'All promises were rejected'));
            }
          });
      });
    });
  }

promise.race

Promise.race() 静态方法接受一个 promise 可迭代对象作为输入,并返回一个 Promise。这个返回的 promise 会随着第一个 promise 的敲定而敲定。

ts
race(promises: PromiseLike<T>[]) {
    return new Promise((resolve, reject) => {
      if (promises.length === 0) return; // 永远 pending
      for (const p of promises) {
        Promise.resolve(p).then(resolve, reject);
      }
    });
  }

promise.allSettled

Promise.allSettled() 静态方法将一个 Promise 可迭代对象作为输入,并返回一个单独的 Promise。当所有输入的 Promise 都已敲定时(包括传入空的可迭代对象时),返回的 Promise 将被兑现,并带有描述每个 Promise 结果的对象数组。

ts
allSettled(promises: PromiseLike<any>[]) {
    return new Promise((resolve) => {
      const result = new Array(promises.length);
      let count = 0;

      promises.forEach((p, i) => {
        Promise.resolve(p)
          .then(value => {
            result[i] = { status: 'fulfilled', value };
          })
          .catch(reason => {
            result[i] = { status: 'rejected', reason };
          })
          .finally(() => {
            count++;
            if (count === promises.length) {
              resolve(result);
            }
          });
      });
    });
  }

promise.withResolvers

Promise.withResolvers() 静态方法返回一个对象,其包含一个新的 Promise 对象和两个函数,用于解决或拒绝它,对应于传入给 Promise() 构造函数执行器的两个参数。

ts
withResolvers() {
    let resolve, reject;
    const promise = new Promise((res, rej) => {
      resolve = res;
      reject = rej;
    });
    return { promise, resolve, reject };
  }

promise.try

Promise.try() 静态方法接受一个任意类型的回调函数(无论其是同步或异步,返回结果或抛出异常),并将其结果封装成一个 Promise

ts
try(fn: Function, ...args: any[]) {
    return new Promise((resolve, reject) => {
      try {
        resolve(fn(...args))
      } catch (err) {
        reject(err);
      }
    });
  }