封装Promise
本文仅根据 Promise A+ 规范实现,与v8引擎提供的Promsie行为略有不同。案例在文章结尾。
准备状态
- 准备promise状态
const enum Status {
pending = 'pending',
fulfilled = 'fulfilled',
rejected = 'rejected'
}
- promise 实例上要有 then,catch,finally 方法,promise支持连续
.调用,所以这三个方法都要返回一个 promise
interface ThenAble {
then(resFunc: (arg: any) => any, rejFunc?: (arg: any) => any): _Promise
catch(res: (arg: any) => any): _Promise
finally(res: (arg: any) => any): _Promise
}
- promise要能够进行状态流转、数据更新,但状态流转、数据更新的方法在外部不允许访问
// 抽象类 定义内部状态
abstract class __Promise {
// 定义 status 保存状态
protected status: Status
// 定义 data 保存数据
protected data: unknown
// 定义状态流转方式
protected abstract toResolve(arg: any): any
protected abstract toReject(arg: any): any
// 初始化状态,数据
constructor() {
this.status = Status.pending
this.data = undefined
}
}
- 创建 _Promise 类继承 __Promise 并实现 ThenAble接口
class _Promise extends __Promise implements ThenAble{
// ... 省去其他部分代码
// 首先实现toResolve 方法
protected toResolve(arg: any) {
// 判断当前 Promise 状态,仅在 pending 状态下更新状态和数据
if (this.status !== Status.pending) {
return
}
this.status = Status.fulfilled
this.data = arg
}
// toreject方法 同上,仅在 pending 状态下更新状态和数据
protected toReject(arg: any) {
if (this.status !== Status.pending) {
return
}
this.status = Status.rejected
this.data = arg
}
// then 方法
then(resFunc: (arg: any) => any, rejFunc?: ((arg: any) => any)): _Promise {
// 保存当前 this 用于在比闭包中查看当前promise状态
const that = this
// 返回 promise 支持连续 . 调用
return new _Promise((res, rej) => {
// 创建 thenCallback 便于之后加入 微任务队列
const doCallback = () => {
// 根据 promise 状态执行不同的回调函数
if (that.status === Status.fulfilled) {
if (typeof resFunc === 'function') {
const data = resFunc(that.data)
// 仅当 resFunc 显示返回一个 promise 时 then 可以返回 rejected 状态的 promise
if (data instanceof _Promise) {
data.then((d) => { res(d) }, d => { rej(d) })
} else {
res(data)
}
}
return
}
// 根据 promise 状态执行不同的回调函数
if (that.status === Status.rejected) {
if (typeof rejFunc === 'function') {
const data = rejFunc(that.data)
// 当传入 rejFunc 时 仅在 rejFunc 显示返回一个 promise 时 then 可能返回一个 rejected 状态的 promise
if (data instanceof _Promise) {
data.then(d => res(d), d => rej(d))
} else {
res(data)
}
}
// 未传入 rejFunc 时,将当前 promise 状态、数据传递给 then 返回的 promise
else {
rej(that.data)
}
return
}
// promise 仍为 pending 状态 创建宏任务,将 thenCallback 再次加入到微任务队列
setTimeout(() => { queueMicrotask(doCallback) })
}
queueMicrotask(doCallback)
})
}
// catch 方法 和 then 方法相同思路,但只在 promise 状态为 rejected 时执行回调
catch(catchFunc: (arg: any) => any): _Promise {
const that = this
return new _Promise(((res, rej) => {
const catchCallback = () => {
// 仅在当前状态为 pending 时将 catchCallback 再次加入到微任务队列
if (that.status === Status.pending) {
setTimeout(() => { queueMicrotask(catchCallback) })
return
}
// 当 promise 状态为 rejected 时执行回调
if (that.status === Status.rejected) {
if (typeof catchFunc === 'function') {
const data = catchFunc(that.data)
// 当传入 rejFunc 时 仅在 rejFunc 显式返回一个 promise 时 then 可能返回一个 rejected 状态的 promise
if (data instanceof _Promise) {
data.then(d => res(d), d => rej(d))
return
}
res(data)
}
}
res(that.data)
}
queueMicrotask(catchCallback)
}))
}
// finally 方法 思路同上
finally(finallyFunc: (arg: any) => any): _Promise {
const that = this
return new _Promise((res, rej) => {
const finallyCallback = () => {
if (that.status === Status.pending) {
setTimeout(() => queueMicrotask(finallyCallback))
return
}
if (typeof finallyFunc === 'function') {
const data = finallyFunc(that.data)
if (data instanceof _Promise) {
data.then((d) => res(d), d => rej(d))
return
}
res(data)
}
}
queueMicrotask(finallyCallback)
})
}
}
- 添加 _Promise 的静态方法
class _Promise extends __Promise implements ThenAble {
// 省去部分代码
// resolve 方法 返回一个 fulfilled 状态的 promise
static resolve(arg: unknown): _Promise {
return new _Promise((res) => res(arg))
}
// reject 方法,返回一个 rejected 状态的 Promise
static reject(arg: unknown): _Promise {
return new _Promise((res, rej) => rej(arg))
}
// race 方法 根据传入promise数组最先落定状态的promise确定返回 Promise的状态和参数
static race(arg: _Promise[]): _Promise {
return new _Promise((res, rej) => {
// 对所有传入的 promise 调用 then 方法,在 then 方法传入的回调中 更改当前 promise 的状态
arg.forEach(item => {
item.then(data => {
res(data)
}, data => {
rej(data)
}
)
})
})
}
// all 方法 传入的promise数组全部 fulfilled之后完成,如果传入的promise数组出现rejected,返回rejected状态的promise
static all(arg: _Promise[]): _Promise {
const status: Status[] = []
const data: any[] = []
return new _Promise((res, rej) => {
arg.forEach((item, index) => {
status[index] = Status.pending
item.then(d => {
// 记录当前 promise 的位置数据,状态
data[index] = d
status[index] = Status.fulfilled
}, d => {
// 当传入的 promise 存在 rejected 状态时,直接将 race 返回的 promise 置为 rejected 状态
rej(d)
})
})
const allCallback = () => {
// 轮询方式与 then 方法中类似
if (status.some(item => item === Status.rejected)) {
return
}
if (status.every(item => {
return item !== Status.pending
})) {
res(data)
return
}
setTimeout(() => { queueMicrotask(allCallback) })
}
queueMicrotask(allCallback)
})
}
// allSettled 方法,返回 一个Promise当所有传入promise状态落定后完成
static allSettled(arg: _Promise[]): _Promise {
const data: any[] = []
const status: Status[] = []
arg.forEach((item, index) => {
status[index] = Status.pending
item.then((res) => {
data[index] = res
status[index] = Status.fulfilled
}, res => {
// 与 all 方法不同,该方法在数组中存在 rejected 状态的 promise 时不会直接置为 rejected 而是一样记录数据状态
data[index] = res
status[index] = Status.rejected
})
})
return new _Promise((res, rej) => {
const allSettledCallback = () => {
if (status.some(item => item === Status.pending)) {
setTimeout(() => { queueMicrotask(allSettledCallback) })
return
}
res(data.map((item, index) => {
// 将传入的 promise 的结果以对象数组的形式传递
return {
status: status[index],
value: item
}
}))
}
queueMicrotask(allSettledCallback)
})
}
}
完整代码
// 准备 promise 状态
const enum Status {
pending = 'pending',
fulfilled = 'fulfilled',
rejected = 'rejected'
}
// promise 对象中要有 then,catch,finally 方法
interface ThenAble {
then(resFunc: (arg: any) => any, rejFunc?: (arg: any) => any): _Promise
catch(res: (arg: any) => any): _Promise
finally(res: (arg: any) => any): _Promise
}
// 抽象类 定义内部状态
abstract class __Promise {
// 定义 status 保存状态
protected status: Status
// 定义 data 保存数据
protected data: unknown
// 定义状态流转方式
protected abstract toResolve(arg: any): any
protected abstract toReject(arg: any): any
// 初始化状态,数据
constructor() {
this.status = Status.pending
this.data = undefined
}
}
// 创建 _Promise 实现 ThenAble 接口
class _Promise extends __Promise implements ThenAble {
// Promise 状态,外部不可读取
protected status: Status
// Promise 数据,外部不可读取
protected data: unknown
// resolve 方法,返回一个 fulfilled 状态的 Promise
static resolve(arg: unknown): _Promise {
return new _Promise((res) => res(arg))
}
// reject 方法,返回一个 rejected 状态的 Promise
static reject(arg: unknown): _Promise {
return new _Promise((res, rej) => rej(arg))
}
// race 方法 根据传入promise数组最先落定状态的promise确定返回 Promise的状态和参数
static race(arg: _Promise[]): _Promise {
return new _Promise((res, rej) => {
// 对所有传入的 promise 调用 then 方法,在 then 方法传入的回调中 更改当前 promise 的状态
arg.forEach(item => {
item.then(data => {
res(data)
}, data => {
rej(data)
}
)
})
})
}
// all 方法 传入的promise数组全部 fulfilled之后完成,如果传入的promise数组出现rejected,返回rejected状态的promise
static all(arg: _Promise[]): _Promise {
const status: Status[] = []
const data: any[] = []
return new _Promise((res, rej) => {
arg.forEach((item, index) => {
status[index] = Status.pending
item.then(d => {
// 记录当前 promise 的位置数据,状态
data[index] = d
status[index] = Status.fulfilled
}, d => {
// 当传入的 promise 存在 rejected 状态时,直接将 race 返回的 promise 置为 rejected 状态
rej(d)
})
})
const allCallback = () => {
// 轮询方式与 then 方法中类似
if (status.some(item => item === Status.rejected)) {
return
}
if (status.every(item => {
return item !== Status.pending
})) {
res(data)
return
}
setTimeout(() => { queueMicrotask(allCallback) })
}
queueMicrotask(allCallback)
})
}
// allSettled 方法,返回 一个Promise当所有传入promise状态落定后完成
static allSettled(arg: _Promise[]): _Promise {
const data: any[] = []
const status: Status[] = []
arg.forEach((item, index) => {
status[index] = Status.pending
item.then((res) => {
data[index] = res
status[index] = Status.fulfilled
}, res => {
// 与 all 方法不同,该方法在数组中存在 rejected 状态的 promise 时不会直接置为 rejected 而是一样记录数据状态
data[index] = res
status[index] = Status.rejected
})
})
return new _Promise((res, rej) => {
const allSettledCallback = () => {
if (status.some(item => item === Status.pending)) {
setTimeout(() => { queueMicrotask(allSettledCallback) })
return
}
res(data.map((item, index) => {
// 将传入的 promise 的结果以对象数组的形式传递
return {
status: status[index],
value: item
}
}))
}
queueMicrotask(allSettledCallback)
})
}
constructor(func: (resolve: (arg: unknown) => void, reject: (arg: unknown) => void) => unknown) {
super()
// 传入 toResolve 和 toReject 方法,并绑定this
typeof func === 'function' && func(this.toResolve.bind(this), this.toReject.bind(this))
}
// toResolve 将promise 状态转换为 fulfilled,外部不可访问
protected toResolve(arg: any) {
// 判断当前 Promise 状态,仅在 pending 状态下更新状态和数据
if (this.status !== Status.pending) {
return
}
this.status = Status.fulfilled
this.data = arg
}
// toreject方法 同上,仅在 pending 状态下更新状态和数据
protected toReject(arg: any) {
if (this.status !== Status.pending) {
return
}
this.status = Status.rejected
this.data = arg
}
// then 方法
then(resFunc: (arg: any) => any, rejFunc?: ((arg: any) => any)): _Promise {
// 保存当前 this 用于在比闭包中查看当前promise状态
const that = this
// 返回 promise 支持连续 . 调用
return new _Promise((res, rej) => {
// 创建 thenCallback 便于之后加入 微任务队列
const doCallback = () => {
// 根据 promise 状态执行不同的回调函数
if (that.status === Status.fulfilled) {
if (typeof resFunc === 'function') {
const data = resFunc(that.data)
// 仅当 resFunc 显示返回一个 promise 时 then 可以返回 rejected 状态的 promise
if (data instanceof _Promise) {
data.then((d) => { res(d) }, d => { rej(d) })
} else {
res(data)
}
}
return
}
// 根据 promise 状态执行不同的回调函数
if (that.status === Status.rejected) {
if (typeof rejFunc === 'function') {
const data = rejFunc(that.data)
// 当传入 rejFunc 时 仅在 rejFunc 显示返回一个 promise 时 then 可能返回一个 rejected 状态的 promise
if (data instanceof _Promise) {
data.then(d => res(d), d => rej(d))
} else {
res(data)
}
}
// 未传入 rejFunc 时,将当前 promise 状态、数据传递给 then 返回的 promise
else {
rej(that.data)
}
return
}
// promise 仍为 pending 状态 创建宏任务,将 thenCallback 再次加入到微任务队列
setTimeout(() => { queueMicrotask(doCallback) })
}
queueMicrotask(doCallback)
})
}
// catch 方法 和 then 方法相同思路,但只在 promise 状态为 rejected 时执行回调
catch(catchFunc: (arg: any) => any): _Promise {
const that = this
return new _Promise(((res, rej) => {
const catchCallback = () => {
// 仅在当前状态为 pending 时将 catchCallback 再次加入到微任务队列
if (that.status === Status.pending) {
setTimeout(() => { queueMicrotask(catchCallback) })
return
}
// 当 promise 状态为 rejected 时执行回调
if (that.status === Status.rejected) {
if (typeof catchFunc === 'function') {
const data = catchFunc(that.data)
// 当传入 rejFunc 时 仅在 rejFunc 显式返回一个 promise 时 then 可能返回一个 rejected 状态的 promise
if (data instanceof _Promise) {
data.then(d => res(d), d => rej(d))
return
}
res(data)
}
}
res(that.data)
}
queueMicrotask(catchCallback)
}))
}
// finally 方法 思路同上
finally(finallyFunc: (arg: any) => any): _Promise {
const that = this
return new _Promise((res, rej) => {
const finallyCallback = () => {
if (that.status === Status.pending) {
setTimeout(() => queueMicrotask(finallyCallback))
return
}
if (typeof finallyFunc === 'function') {
const data = finallyFunc(that.data)
if (data instanceof _Promise) {
data.then((d) => res(d), d => rej(d))
return
}
res(data)
}
}
queueMicrotask(finallyCallback)
})
}
}
未经过严密测试,如有问题请评论告诉我
注:该实现与v8引擎提供的 promise 在行为上略有差异
// const _Promise = Promise
_Promise
.resolve(undefined)
.then(() => {
console.log(0);
return _Promise.resolve(4);
})
.then((res) => console.log(res));
_Promise
.resolve(undefined)
.then((_) => {
console.log(1);
})
.then((_) => {
console.log(2);
})
.then((_) => {
console.log(3);
})
.then((_) => {
console.log(5);
})
.then((_) => {
console.log(6);
});
// v8 引擎下 该案例输出 0 1 2 3 4 5 6
// 本文实现下 该案例输出 0 1 2 3 5 6 4
本文根据Promise A+规范详细讲解如何封装一个Promise,重点介绍准备状态和Promise实例的方法如then、catch、finally。虽然与v8引擎的Promise行为有差异,但提供了完整的实现代码供参考。
396

被折叠的 条评论
为什么被折叠?



