Skip to content

TS 手写 Promise 并通过 Promise/A+ 规范 872 条用例的方法 #81

@inkjuncom

Description

@inkjuncom

环境准备

1. 测试集准备

npm i promises-aplus-test

这是 Promise/A+ 的测试集

我们可以新增 test 命令 promises-aplus-tests inkPromise

promises-aplus-tests 是 Promise/A+ 的测试级

待会直接运行 npm run test 就可以测试自己实现的 inkPromise.js

2. ts 环境准备

npm i typescript @types/node -D

我们可以新增 build 命令 tsc inkPromise.ts

typescript 用来编译 ts, @types/node 这是用来解决 ts 不认识 module.exports 的类型报错

待会直接运行 npm run build 就可以把 inkPromise.ts 编译为 inkPromise.js

3. 文件导出准备

我们实现的 inkPromise 在一个 inkPromise.ts 里面, 它会导出 2 个东西:

interface Defered<T> {
  // ...
}

class InkPromise<T> {
  // ...
  static deferred<T>(): Defered<T> {

  }
}

function resolvePromise<T> {

}

module.exports = InkPromise
  1. 文件运行准备

编写 InkPromise 过程中, 我们应该常常需要直接运行 inkPromise.ts 文件,

npm i ts-node -D

前 3 节准备结束, package.json 内容应该如下:

{
  // ...
  "scripts": {
    "build": "tsc inkPromise.ts",
    "test": "promises-aplus-tests inkPromise"
  },
  "dependencies": {
    "promises-aplus-tests": "^2.1.2"
  },
  "devDependencies": {
    "@types/node": "^24.10.2",
    "typescript": "^5.9.3"
  }
}

开始编写

定义初始结构

type ResolveFunc<T> = (value: T | PromiseLike<T>) => void
type RejectFunc = (reason: unknown) => void;
type Executor<T> = (resolve: ResolveFunc<T>, reject: RejectFunc) => void

class INKPromise<T> {
  constructor(func: Executor<T>) {

  }
}

因为正常 Promise 创建时, 是这样的:

new Promise((resolve, reject))

其中 resolve 函数的入参, 既可以接受普通参数, 也可以接受 Promise

const p1 = new Promise((resolve) => resolve('ink'))

const p2 = new Promise((resolve) => resolve(Promise.resolve('ink')))

PromiseLike 是 TypeScript 内置类型,表示任何具有 .then() 方法的对象, 也就是 thenable 对象

通常来说,不建议将 RejectFunc 的参数类型写成 T。写成 any (或者 unknown) 才是符合 Promise 标准且更实用的做法。

以下是详细的原因分析和修改建议:

为什么不能写成 reason: T?

成功值与失败原因通常类型不同:

泛型 T 代表的是 Promise 成功(Fulfilled) 时返回的数据类型。

Promise 失败(Rejected) 时,通常抛出的是一个 Error 对象,或者字符串错误信息,而不是数据本身。

举例:如果你定义 new INKPromise(...),这意味着成功时返回 number。如果 RejectFunc 也是 (reason: number) => void,那你就只能用数字来报错,无法抛出 new Error("出错了"),这显然不合理。

try-catch 的兼容性:

在执行器(Executor)中,我们经常捕获异常并 reject。JavaScript 的 catch(e) 捕获到的 e 类型是不确定的(通常视为 any 或 unknown)。

如果 reject 强制要求类型 T,你就无法直接把捕获的错误传给它。

代码演示
如果写成 reason: T,会遇到这种尴尬的情况:

const p = new INKPromise<User>((resolve, reject) => {
  // 模拟请求
  if (success) {
    resolve({ name: 'Tom', age: 18 }); // ✅ 正常,类型匹配 User
  } else {
    // ❌ 报错!因为 reject 期望参数是 User 类型,但你传的是 Error
    reject(new Error('网络错误')); 
  }
});

实现 resolve 和 reject 的类型

type ResolveFunc<T> = (value: T | PromiseLike<T>) => void
type RejectFunc = (reason: unknown) => void;
type Executor<T> = (resolve: ResolveFunc<T>, reject: RejectFunc) => void

class INKPromise<T> {
  constructor(func: Executor<T>) {
    func(this.resolve, this.reject)
  }
  resolve: ResolveFunc<T> = () => {

  }
  reject: RejectFunc = () => {

  }
}

管理状态

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

type ResolveFunc<T> = (value: T | PromiseLike<T>) => void
type RejectFunc = (reason: unknown) => void;
type Executor<T> = (resolve: ResolveFunc<T>, reject: RejectFunc) => void

class INKPromise<T> {
  private promiseState: STATE;
  constructor(func: Executor<T>) {
    this.promiseState = STATE.PENDING
    func(this.resolve, this.reject)
  }
  resolve: ResolveFunc<T> = () => {
    if (this.promiseState === STATE.PENDING) {
      this.promiseState = STATE.FULFILLED
    }
  }
  reject: RejectFunc = () => {
    if (this.promiseState === STATE.PENDING) {
      this.promiseState = STATE.REJECTED
    }
  }
}

resolve 和 reject 可以传参

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

type ResolveFunc<T> = (value: T | PromiseLike<T>) => void
type RejectFunc = (reason: unknown) => void;
type Executor<T> = (resolve: ResolveFunc<T>, reject: RejectFunc) => void

class INKPromise<T> {
  private promiseState: STATE;
  private promiseResult: unknown
  constructor(func: Executor<T>) {
    this.promiseState = STATE.PENDING
    this.promiseResult = null
    func(this.resolve, this.reject)
  }
  resolve: ResolveFunc<T> = (result) => {
    if (this.promiseState === STATE.PENDING) {
      this.promiseState = STATE.FULFILLED
      this.promiseResult = result
    }
  }
  reject: RejectFunc = (reason) => {
    if (this.promiseState === STATE.PENDING) {
      this.promiseState = STATE.REJECTED
      this.promiseResult = reason
    }
  }
}

bind 指向问题

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

type ResolveFunc<T> = (value: T | PromiseLike<T>) => void
type RejectFunc = (reason: unknown) => void;
type Executor<T> = (resolve: ResolveFunc<T>, reject: RejectFunc) => void

class INKPromise<T> {
  private promiseState: STATE;
  private promiseResult: unknown
  constructor(func: Executor<T>) {
    this.promiseState = STATE.PENDING
    this.promiseResult = null
    func(this.resolve.bind(this), this.reject.bind(this))
  }
  resolve: ResolveFunc<T> = (result) => {
    if (this.promiseState === STATE.PENDING) {
      this.promiseState = STATE.FULFILLED
      this.promiseResult = result
    }
  }
  reject: RejectFunc = (reason) => {
    if (this.promiseState === STATE.PENDING) {
      this.promiseState = STATE.REJECTED
      this.promiseResult = reason
    }
  }
}

实现 then 方法

回顾下 then 的使用方法

const p = new Promise((resolve) => {
  setTimeout(() => {
    resolve('Hello World')
  }, 1000)
})

p.then(res => {
  console.log(res)
})

但很多时候, .then 里面的 OnFulfilled 会改变数据的类型

举个例子:

假设你有一个 INKPromise(比如是一个 HTTP 请求返回的 JSON 字符串),你想把它解析成对象,或者计算字符串长度(变成数字)。

// 1. 初始 Promise 是 string 类型 (T = string)
const p1 = new INKPromise<string>((resolve) => resolve("hello"));

// 2. 调用 then
const p2 = p1.then<number>(
  // onFulfilled 回调
  (value) => { 
    // value 的类型是 T (string)
    console.log(value); 
    
    // 返回值的类型是 TResult1 (number)
    return value.length;
  }
);

// 3. p2 变成了 INKPromise<number>

所以我们在定义 onFulfilled 时, 需要用到两个泛型变量

默认泛型参数 = T 和 = never

TResult1 = T: 如果用户没有传 onFulfilled(即 undefined),那么 Promise 的值会原样传递下去。所以默认类型应该是当前的 T。

TResult2 = never: 如果用户没有传 onRejected,通常意味着错误会继续抛出,不会产生新的值,所以默认是 never。

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

type ResolveFunc<T> = (value: T | PromiseLike<T>) => void
type RejectFunc = (reason: unknown) => void;
type Executor<T> = (resolve: ResolveFunc<T>, reject: RejectFunc) => void

type OnFulfilled<T, TResult> = ((value: T) => TResult | Promise<TResult>) | unknown
type OnRejected<TResult> = ((reason: unknown) => TResult) | unknown

class InkPromise<T> {
  private promiseState: STATE
  private promiseResult: unknown
  constructor(func: Executor<T>) {
    this.promiseState = STATE.PENDING
    this.promiseResult = null
    func(this.resolve.bind(this), this.reject.bind(this))
  }
  resolve: ResolveFunc<T> = (result) => {
    if (this.promiseState === STATE.PENDING) {
      this.promiseState = STATE.FULFILLED
      this.promiseResult = result
    }
  }
  reject: RejectFunc = (reason) => {
    if (this.promiseState === STATE.PENDING) {
      this.promiseState = STATE.REJECTED
      this.promiseResult = reason
    }
  }
  then<TResult1 = T, TResult2 = never>(
    onFulfilled?: OnFulfilled<T, TResult1>,
    onRejected?: OnRejected<TResult2>
  ): InkPromise<TResult1 | TResult2> {
    const promise2 = new InkPromise<TResult1 | TResult2>(() => {

    })
    return promise2
  }
}

状态不可变

Promise 状态确定后, 就不会再改变, 再 then 阶段, 我们需要把结构传递给 onFulfilled 和 onRejected 方法

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

type ResolveFunc<T> = (value: T | PromiseLike<T>) => void
type RejectFunc = (reason: unknown) => void;
type Executor<T> = (resolve: ResolveFunc<T>, reject: RejectFunc) => void

type OnFulfilled<T, TResult> = ((value: T) => TResult | Promise<TResult>) | unknown
type OnRejected<TResult> = ((reason: unknown) => TResult) | unknown 

class InkPromise<T> {
  private promiseState: STATE
  private promiseResult: unknown
  constructor(func: Executor<T>) {
    this.promiseState = STATE.PENDING
    this.promiseResult = null
    func(this.resolve.bind(this), this.reject.bind(this))
  }
  resolve: ResolveFunc<T> = (result) => {
    if (this.promiseState === STATE.PENDING) {
      this.promiseState = STATE.FULFILLED
      this.promiseResult = result
    }
  }
  reject: RejectFunc = (reason) => {
    if (this.promiseState === STATE.PENDING) {
      this.promiseState = STATE.REJECTED
      this.promiseResult = reason
    }
  }
  then<TResult1 = T, TResult2 = never>(
    onFulfilled?: OnFulfilled<T, TResult1>,
    onRejected?: OnRejected<TResult2>
  ): InkPromise<TResult1 | TResult2> {
    const promise2 = new InkPromise<TResult1 | TResult2>(() => {
      if (this.promiseState === STATE.FULFILLED) {
        if (typeof onFulfilled === 'function') {
          onFulfilled(this.promiseResult)
        }
      } else if (this.promiseState === STATE.REJECTED) {
        if (typeof onRejected === 'function') {
          onRejected(this.promiseResult)
        }
      }
    })
    return promise2
  }
}

处理不是函数的参数

新手常误以为 .then(value) 会把结果变成那个值,但实际上如果传入的不是函数,Promise 会忽略它,并将上一个 Promise 的结果直接传递给下一个 .then。

Promise.resolve('原始值')
  .then(1)             // ❌ 传入了数字,不是函数 -> 被忽略
  .then('我是字符串')   // ❌ 传入了字符串,不是函数 -> 被忽略
  .then({})            // ❌ 传入了对象,不是函数 -> 被忽略
  .then((res) => {
    console.log(res);  // ✅ 输出: "原始值"
  });
enum STATE {
  PENDING = 'pending',
  FULFILLED = 'fulfilled',
  REJECTED = 'rejected'
}

type ResolveFunc<T> = (value: T | PromiseLike<T>) => void
type RejectFunc = (reason: unknown) => void;
type Executor<T> = (resolve: ResolveFunc<T>, reject: RejectFunc) => void

type OnFulfilled<T, TResult> = ((value: T) => TResult | Promise<TResult>) | unknown
type OnRejected<TResult> = ((reason: unknown) => TResult) | unknown 

class InkPromise<T> {
  private promiseState: STATE
  private promiseResult: unknown
  constructor(func: Executor<T>) {
    this.promiseState = STATE.PENDING
    this.promiseResult = null
    func(this.resolve.bind(this), this.reject.bind(this))
  }
  resolve: ResolveFunc<T> = (result) => {
    if (this.promiseState === STATE.PENDING) {
      this.promiseState = STATE.FULFILLED
      this.promiseResult = result
    }
  }
  reject: RejectFunc = (reason) => {
    if (this.promiseState === STATE.PENDING) {
      this.promiseState = STATE.REJECTED
      this.promiseResult = reason
    }
  }
  then<TResult1 = T, TResult2 = never>(
    onFulfilled?: OnFulfilled<T, TResult1>,
    onRejected?: OnRejected<TResult2>
  ): InkPromise<TResult1 | TResult2> {
    const promise2 = new InkPromise<TResult1 | TResult2>((resolve, reject) => {
      if (this.promiseState === STATE.FULFILLED) {
        if (typeof onFulfilled === 'function') {
          onFulfilled(this.promiseResult)
        } else {
          resolve(this.promiseResult as unknown as TResult1)
        }
      } else if (this.promiseState === STATE.REJECTED) {
        if (typeof onRejected === 'function') {
          onRejected(this.promiseResult)
        } else {
          reject(this.promiseResult as unknown as TResult2)
        }
      }
    })
    return promise2
  }
}

执行异常状态 throw

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

type ResolveFunc<T> = (value: T | PromiseLike<T>) => void
type RejectFunc = (reason: unknown) => void;
type Executor<T> = (resolve: ResolveFunc<T>, reject: RejectFunc) => void

type OnFulfilled<T, TResult> = ((value: T) => TResult | Promise<TResult>) | unknown
type OnRejected<TResult> = ((reason: unknown) => TResult) | unknown 

class InkPromise<T> {
  private promiseState: STATE
  private promiseResult: unknown
  constructor(func: Executor<T>) {
    this.promiseState = STATE.PENDING
    this.promiseResult = null
    try {
      func(this.resolve.bind(this), this.reject.bind(this))
    } catch (error) {
      this.reject(error)
    }
  }
  resolve: ResolveFunc<T> = (result) => {
    if (this.promiseState === STATE.PENDING) {
      this.promiseState = STATE.FULFILLED
      this.promiseResult = result
    }
  }
  reject: RejectFunc = (reason) => {
    if (this.promiseState === STATE.PENDING) {
      this.promiseState = STATE.REJECTED
      this.promiseResult = reason
    }
  }
  then<TResult1 = T, TResult2 = never>(
    onFulfilled?: OnFulfilled<T, TResult1>,
    onRejected?: OnRejected<TResult2>
  ): InkPromise<TResult1 | TResult2> {
    const promise2 = new InkPromise<TResult1 | TResult2>((resolve, reject) => {
      if (this.promiseState === STATE.FULFILLED) {
        if (typeof onFulfilled === 'function') {
          onFulfilled(this.promiseResult)
        } else {
          resolve(this.promiseResult as unknown as TResult1)
        }
      } else if (this.promiseState === STATE.REJECTED) {
        if (typeof onRejected === 'function') {
          onRejected(this.promiseResult)
        } else {
          reject(this.promiseResult as unknown as TResult2)
        }
      }
    })
    return promise2
  }
}

实现异步

测试代码:

console.log(1);

let promise = new Promise((resolve, reject) => {
    console.log(2);
    resolve('这次一定');
})

promise.then(
    result => {
        console.log('fulfilled:', result);
    },
    reason => {
        console.log('rejected:', reason)
    }
)

console.log(3);

要实现这个, 我们需要在 then 方法里面增加定时器

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

type ResolveFunc<T> = (value: T | PromiseLike<T>) => void
type RejectFunc = (reason: unknown) => void;
type Executor<T> = (resolve: ResolveFunc<T>, reject: RejectFunc) => void

type OnFulfilled<T, TResult> = ((value: T) => TResult | Promise<TResult>) | unknown
type OnRejected<TResult> = ((reason: unknown) => TResult) | unknown 

class InkPromise<T> {
  private promiseState: STATE
  private promiseResult: unknown
  constructor(func: Executor<T>) {
    this.promiseState = STATE.PENDING
    this.promiseResult = null
    try {
      func(this.resolve.bind(this), this.reject.bind(this))
    } catch (error) {
      this.reject(error)
    }
  }
  resolve: ResolveFunc<T> = (result) => {
    if (this.promiseState === STATE.PENDING) {
      this.promiseState = STATE.FULFILLED
      this.promiseResult = result
    }
  }
  reject: RejectFunc = (reason) => {
    if (this.promiseState === STATE.PENDING) {
      this.promiseState = STATE.REJECTED
      this.promiseResult = reason
    }
  }
  then<TResult1 = T, TResult2 = never>(
    onFulfilled?: OnFulfilled<T, TResult1>,
    onRejected?: OnRejected<TResult2>
  ): InkPromise<TResult1 | TResult2> {
    const promise2 = new InkPromise<TResult1 | TResult2>((resolve, reject) => {

      const handleFulfilled = () => {
        setTimeout(() => {
          if (typeof onFulfilled === 'function') {
            onFulfilled(this.promiseResult)
          } else {
            resolve(this.promiseResult as unknown as TResult1)
          }
        })
      }

      const handleRejected = () => {
        setTimeout(() => {
          if (typeof onRejected === 'function') {
            onRejected(this.promiseResult)
          } else {
            reject(this.promiseResult as unknown as TResult2)
          }
        })
      }

      if (this.promiseState === STATE.FULFILLED) {
        handleFulfilled()
      } else if (this.promiseState === STATE.REJECTED) {
        handleRejected()
      }
    })
    return promise2
  }
}

异步 pending 态时, 我们需要不能需要把 promise 暂存一下

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

type ResolveFunc<T> = (value: T | PromiseLike<T>) => void
type RejectFunc = (reason: unknown) => void;
type Executor<T> = (resolve: ResolveFunc<T>, reject: RejectFunc) => void

type OnFulfilled<T, TResult> = ((value: T) => TResult | Promise<TResult>) | unknown
type OnRejected<TResult> = ((reason: unknown) => TResult) | unknown 

class InkPromise<T> {
  private promiseState: STATE
  private promiseResult: unknown
  private onFulfilledCallback: Array<() => void> = []
  private onRejectedCallback: Array<() => void> = []

  constructor(func: Executor<T>) {
    this.promiseState = STATE.PENDING
    this.promiseResult = null
    try {
      func(this.resolve.bind(this), this.reject.bind(this))
    } catch (error) {
      this.reject(error)
    }
  }
  resolve: ResolveFunc<T> = (result) => {
    if (this.promiseState === STATE.PENDING) {
      this.promiseState = STATE.FULFILLED
      this.promiseResult = result
      this.onFulfilledCallback.forEach((callback) => {
        callback()
      })
    }
  }
  reject: RejectFunc = (reason) => {
    if (this.promiseState === STATE.PENDING) {
      this.promiseState = STATE.REJECTED
      this.promiseResult = reason
      this.onRejectedCallback.forEach((callback) => {
        callback()
      })
    }
  }
  then<TResult1 = T, TResult2 = never>(
    onFulfilled?: OnFulfilled<T, TResult1>,
    onRejected?: OnRejected<TResult2>
  ): InkPromise<TResult1 | TResult2> {
    const promise2 = new InkPromise<TResult1 | TResult2>((resolve, reject) => {

      const handleFulfilled = () => {
        setTimeout(() => {
          if (typeof onFulfilled === 'function') {
            onFulfilled(this.promiseResult)
          } else {
            resolve(this.promiseResult as unknown as TResult1)
          }
        })
      }

      const handleRejected = () => {
        setTimeout(() => {
          if (typeof onRejected === 'function') {
            onRejected(this.promiseResult)
          } else {
            reject(this.promiseResult as unknown as TResult2)
          }
        })
      }

      if (this.promiseState === STATE.PENDING) {
        this.onFulfilledCallback.push(handleFulfilled)
        this.onRejectedCallback.push(handleRejected)
      } else if (this.promiseState === STATE.FULFILLED) {
        handleFulfilled()
      } else if (this.promiseState === STATE.REJECTED) {
        handleRejected()
      }
    })
    return promise2
  }
}

解决 Promise 的回调地狱, 实现 then 的链式调用

2.2.7.1 onFulfilled 和 onRejected 的返回值 x, 都会被传递给一个叫 resolvePromise 的函数

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

type ResolveFunc<T> = (value: T | PromiseLike<T>) => void
type RejectFunc = (reason: unknown) => void;
type Executor<T> = (resolve: ResolveFunc<T>, reject: RejectFunc) => void

type OnFulfilled<T, TResult> = ((value: T) => TResult | Promise<TResult>) | unknown
type OnRejected<TResult> = ((reason: unknown) => TResult) | unknown 

class InkPromise<T> {
  private promiseState: STATE
  private promiseResult: unknown
  private onFulfilledCallback: Array<() => void> = []
  private onRejectedCallback: Array<() => void> = []

  constructor(func: Executor<T>) {
    this.promiseState = STATE.PENDING
    this.promiseResult = null
    try {
      func(this.resolve.bind(this), this.reject.bind(this))
    } catch (error) {
      this.reject(error)
    }
  }
  resolve: ResolveFunc<T> = (result) => {
    if (this.promiseState === STATE.PENDING) {
      this.promiseState = STATE.FULFILLED
      this.promiseResult = result
      this.onFulfilledCallback.forEach((callback) => {
        callback()
      })
    }
  }
  reject: RejectFunc = (reason) => {
    if (this.promiseState === STATE.PENDING) {
      this.promiseState = STATE.REJECTED
      this.promiseResult = reason
      this.onRejectedCallback.forEach((callback) => {
        callback()
      })
    }
  }
  then<TResult1 = T, TResult2 = never>(
    onFulfilled?: OnFulfilled<T, TResult1>,
    onRejected?: OnRejected<TResult2>
  ): InkPromise<TResult1 | TResult2> {
    const promise2 = new InkPromise<TResult1 | TResult2>((resolve, reject) => {

      const handleFulfilled = () => {
        setTimeout(() => {
          if (typeof onFulfilled === 'function') {
            let x = onFulfilled(this.promiseResult)
            resolvePromise(promise2, x, resolve, reject)
          } else {
            resolve(this.promiseResult as unknown as TResult1)
          }
        })
      }

      const handleRejected = () => {
        setTimeout(() => {
          if (typeof onRejected === 'function') {
            let x = onRejected(this.promiseResult)
            resolvePromise(promise2, x, resolve, reject)
          } else {
            reject(this.promiseResult as unknown as TResult2)
          }
        })
      }

      if (this.promiseState === STATE.PENDING) {
        this.onFulfilledCallback.push(handleFulfilled)
        this.onRejectedCallback.push(handleRejected)
      } else if (this.promiseState === STATE.FULFILLED) {
        handleFulfilled()
      } else if (this.promiseState === STATE.REJECTED) {
        handleRejected()
      }
    })
    return promise2
  }
}

function resolvePromise<T> (
  promise2: InkPromise<T>,
  x: T | PromiseLike<T> | unknown,
  resolve: ResolveFunc<T>,
  reject: RejectFunc
) {

}

2.2.7.2 如果 onFulfilled 或者 onRejected 抛出一个异常 e ,则 promise2 必须拒绝执行,并返回拒因 e

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

type ResolveFunc<T> = (value: T | PromiseLike<T>) => void
type RejectFunc = (reason: unknown) => void;
type Executor<T> = (resolve: ResolveFunc<T>, reject: RejectFunc) => void

type OnFulfilled<T, TResult> = ((value: T) => TResult | Promise<TResult>) | unknown
type OnRejected<TResult> = ((reason: unknown) => TResult) | unknown 

class InkPromise<T> {
  private promiseState: STATE
  private promiseResult: unknown
  private onFulfilledCallback: Array<() => void> = []
  private onRejectedCallback: Array<() => void> = []

  constructor(func: Executor<T>) {
    this.promiseState = STATE.PENDING
    this.promiseResult = null
    try {
      func(this.resolve.bind(this), this.reject.bind(this))
    } catch (error) {
      this.reject(error)
    }
  }
  resolve: ResolveFunc<T> = (result) => {
    if (this.promiseState === STATE.PENDING) {
      this.promiseState = STATE.FULFILLED
      this.promiseResult = result
      this.onFulfilledCallback.forEach((callback) => {
        callback()
      })
    }
  }
  reject: RejectFunc = (reason) => {
    if (this.promiseState === STATE.PENDING) {
      this.promiseState = STATE.REJECTED
      this.promiseResult = reason
      this.onRejectedCallback.forEach((callback) => {
        callback()
      })
    }
  }
  then<TResult1 = T, TResult2 = never>(
    onFulfilled?: OnFulfilled<T, TResult1>,
    onRejected?: OnRejected<TResult2>
  ): InkPromise<TResult1 | TResult2> {
    const promise2 = new InkPromise<TResult1 | TResult2>((resolve, reject) => {

      const handleFulfilled = () => {
        setTimeout(() => {
          try {
            if (typeof onFulfilled === 'function') {
              let x = onFulfilled(this.promiseResult)
              resolvePromise(promise2, x, resolve, reject)
            } else {
              resolve(this.promiseResult as unknown as TResult1)
            }
          } catch (e) {
            reject(e)
          }
        })
      }

      const handleRejected = () => {
        setTimeout(() => {
          try {
            if (typeof onRejected === 'function') {
              let x = onRejected(this.promiseResult)
              resolvePromise(promise2, x, resolve, reject)
            } else {
              reject(this.promiseResult as unknown as TResult2)
            }
          } catch (e) {
            reject(e)
          }
        })
      }

      if (this.promiseState === STATE.PENDING) {
        this.onFulfilledCallback.push(handleFulfilled)
        this.onRejectedCallback.push(handleRejected)
      } else if (this.promiseState === STATE.FULFILLED) {
        handleFulfilled()
      } else if (this.promiseState === STATE.REJECTED) {
        handleRejected()
      }
    })
    return promise2
  }
}

function resolvePromise<T> (
  promise2: InkPromise<T>,
  x: T | PromiseLike<T> | unknown,
  resolve: ResolveFunc<T>,
  reject: RejectFunc
) {

}

实现 resolvePromise 方法

2.3.1 如果 promise 和 x 指向同一对象,以 TypeError 为据因拒绝执行 promise

2.3.2 如果 x 为 Promise ,则使 promise 接受 x 的状态

2.3.3 https://malcolmyu.github.io/2015/06/12/Promises-A-Plus/

function resolvePromise<T> (
  promise2: InkPromise<T>,
  x: T | PromiseLike<T> | unknown,
  resolve: ResolveFunc<T>,
  reject: RejectFunc
) {
  if (x === promise2) {
    throw new TypeError("Chaining cycle detected for promise")
  }

  if (x instanceof InkPromise) {
    x.then(
      (y: unknown) => {
        resolvePromise(promise2, y, resolve, reject)
      },
      reject
    )
  } else if (x !== null && (typeof x === 'object') || (typeof x === 'function')) {
    let then: unknown
    try {
      then = (x as { then: unknown }).then
    } catch (e) {
      return reject(e)
    }

    if (typeof then === 'function') {
      let called = false
      try {
        then.call(
          x,
          (y: unknown) => {
            if (called) { return }
            called = true
            resolvePromise(promise2, y, resolve, reject)
          },
          (r: unknown) => {
            if (called) { return }
            called = true
            reject(r)
          }
        )
      } catch (e) {
        if (called) { return }
        called = true
        reject(e)
      }
    } else {
      resolve(x as T)
    }
  } else {
    resolve(x as T)
  }
}

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions