简单实现
首先,实现这个最简单的使用方式
new Promise((resolve, reject) => {
resolve(1)
})
分析一下,Promise 实例接受一个 Function,Function 接受两个参数,分别为 resolve,reject 实现:
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 有三种状态,分别是pending
,fulfilled
和rejected
,初始状态为 pending,pending 可以转为 fulfilled(resolve) 和 rejected(reject),状态不可逆转,fulfilled 和 rejected 也不可以互相转。
定义状态枚举:
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:
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 指向的八股文
JS
的this
指向取决于环境。
全局环境中的this
,直接指向全局对象。
函数环境中的this
,取决于函数如何被调用:
- 如果函数是直接调用的,同时又是出于严格模式下,则指向
undefined
,如果不是严格模式,则指向全局对象 - 如果函数是通过一个对象调用的,则指向对象本身
- 如果函数是通过一些特殊方法调用的,比如
call
、apply
、bind
,通过这些方法调用的话,则指向指定的对象 - 如果函数是通过
new
调用的,则指向新的实例。 另外,箭头函数由于没有this
,所以箭头函数内部的this
由其外部作用域决定。
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 中
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的实现,依旧是一个简单的示例
new Promise((resolve, reject) => {
resolve(1)
}).then((res) => {}, (reason) => {})
分析一下,这里的 then 接收两个参数,第一个是 resolve 时触发的回调,第二个是 reject 触发的回调。很轻松就可以做到这一点。
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)
}
}
}
测试一下目前的功能:
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来实现。
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 中打印一下每个阶段的状态:
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 调用时再触发。
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。
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 最麻烦的部分。
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。
这里借用一下大佬的总结:
- then方法本身会返回一个新的Promise对象,返回一个新的Promise以后它就有自己的then方法,这样就能实现无限的链式。
- 不论 promise1 被 resolve() 还是被 reject() 时 promise2 都会执行 Promise 解决过程:Resolve(promise2, x)
先来实现then方法中返回一个新 promise
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 解决过程。
// 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 为原因被拒绝。
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 状态中的处理。
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
相同的值被满足
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 相同的原因被拒绝。
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
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
。
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
。
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
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
都被调用,或者对同一个参数进行了多次调用,则第一次调用具有优先级,后续的调用将被忽略。
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
。
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
。
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
工具测试:
最后完善一下类型。
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 将被拒绝,并带有第一个被拒绝的原因。
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 拒绝。
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 的敲定而敲定。
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 结果的对象数组。
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() 构造函数执行器的两个参数。
withResolvers() {
let resolve, reject;
const promise = new Promise((res, rej) => {
resolve = res;
reject = rej;
});
return { promise, resolve, reject };
}
promise.try
Promise.try()
静态方法接受一个任意类型的回调函数(无论其是同步或异步,返回结果或抛出异常),并将其结果封装成一个 Promise。
try(fn: Function, ...args: any[]) {
return new Promise((resolve, reject) => {
try {
resolve(fn(...args))
} catch (err) {
reject(err);
}
});
}