promise的状态
const PromiseStatus = {
PENDING: "pending",
FULFILLED: "fulfilled",
REJECTED: "rejected"
}
如上图所示, promise的几个状态之间的关系,接下来我们将一步步实现一个自己的CustomPromise
开始构建promise对象
class CustomPromise {
status = PromiseStatus.PENDING
data = null
error = null
constructor(executor) {
const resolve = (data) => {}
const reject = (error) => {}
executor(resolve, reject)
}
}
如上代码所示, 当我们new Promise()时到到底是如何执行的,
推进promise的状态
1. reject时
const rejectPromise = (promise, reason) => {
if (promise.status !== PromiseStatus.PENDING) {
return
}
promise.status = PromiseStatus.REJECTED
promise.error = reason
promise._flushHandlers()
}
class CustomPromise {
status = PromiseStatus.PENDING
data = null
error = null
constructor(executor) {
const resolve = (data) => { }
const reject = (error) => {
rejectPromise(this, error)
}
executor(resolve, reject)
}
}
如上所示, 我们在reject后将状态推进为rejected,并记录错误信息error
挂载then方法
众所周知, promise的实例是可以连续then的,然后后面then回调函数的入参是由前面的then回调函数的返回值决定的, 是有链式影响效果的, 所以调用then方法后是返回一个promise实例的, 以用于后面继续then或者catch
then(successCallback, errorCallback) {
const promise = new CustomPromise(() => { })
this.#onFulfilledCallbacks.push({
successCallback,
errorCallback,
promise
})
return promise
}
在这段代码, 我记录了then所挂载的新任务, 以方便resolve之后执行
调用promise的then方法所挂载的任务
const isFunction = (value) => value && typeof value === "function"
const resolvePromise = (promise, info) => {
if (promise.status !== PromiseStatus.PENDING) {
return
}
// 判断info是不是和当前实例对象相同
// console.log("判断info是不是和当前实例对象相同", info === this);
if (promise === info) {
const error = new TypeError("Chaining cycle detected for promise #<CustomPromise>")
rejectPromise(promise, error)
throw error;
}
// 判断对象是不是一个thenable对象
if (!promise.isThenable(info)) {
promise.status = PromiseStatus.FULFILLED
promise.data = info
promise._flushHandlers()
return
}
// 当前info是一个thenable对象, 当前实例需要吸收info的状态
queueMicrotask(() => {
// 吸收对象的过程是在微队列进行的
info.then((res) => {
resolvePromise(promise, res)
}, (err) => {
rejectPromise(promise, err)
})
})
}
_flushHandlers() {
if (this.status === PromiseStatus.PENDING) {
return
}
queueMicrotask(() => {
while (this.#onFulfilledCallbacks.length) {
const {
successCallback,
errorCallback,
promise
} = this.#onFulfilledCallbacks.shift();
if (!isFunction(successCallback) && this.status === PromiseStatus.FULFILLED) {
resolvePromise(promise, this.data)
continue;
}
if (!isFunction(errorCallback) && this.status === PromiseStatus.REJECTED) {
console.log('task', promise);
rejectPromise(promise, this.status)
continue;
}
if(this.status === PromiseStatus.FULFILLED){
resolvePromise(promise, successCallback(this.data))
continue;
}
if(this.status === PromiseStatus.REJECTED){
rejectPromise(promise, errorCallback(this.error))
continue;
}
}
})
}
首先, 如果当前实例状态并未更新到完成状态(fulfilled和rejected统称为完成状态), 说明未到回调任务之时, 其次, 若是then方法中所传参数不是函数, 则更新返回的实例的状态和参数即可
更新完所有状态后, 我们的promise实例也算是走完了整个流程, 下面奉上所有源码
const PromiseStatus = {
PENDING: "pending",
FULFILLED: "fulfilled",
REJECTED: "rejected"
}
const isFunction = (value) => value && typeof value === "function"
const rejectPromise = (promise, reason) => {
if (promise.status !== PromiseStatus.PENDING) {
return
}
promise.status = PromiseStatus.REJECTED
promise.error = reason
promise._flushHandlers()
}
const resolvePromise = (promise, info) => {
if (promise.status !== PromiseStatus.PENDING) {
return
}
// 判断info是不是和当前实例对象相同
// console.log("判断info是不是和当前实例对象相同", info === this);
if (promise === info) {
const error = new TypeError("Chaining cycle detected for promise #<CustomPromise>")
rejectPromise(promise, error)
throw error;
}
// 判断对象是不是一个thenable对象
if (!promise.isThenable(info)) {
promise.status = PromiseStatus.FULFILLED
promise.data = info
promise._flushHandlers()
return
}
// 当前info是一个thenable对象, 当前实例需要吸收info的状态
queueMicrotask(() => {
// 吸收对象的过程是在微队列进行的
info.then((res) => {
resolvePromise(promise, res)
}, (err) => {
rejectPromise(promise, err)
})
})
}
class CustomPromise {
status = PromiseStatus.PENDING
data = null
error = null
#onFulfilledCallbacks = []
_flushHandlers() {
if (this.status === PromiseStatus.PENDING) {
return
}
queueMicrotask(() => {
while (this.#onFulfilledCallbacks.length) {
const {
successCallback,
errorCallback,
promise
} = this.#onFulfilledCallbacks.shift();
if (!isFunction(successCallback) && this.status === PromiseStatus.FULFILLED) {
resolvePromise(promise, this.data)
continue;
}
if (!isFunction(errorCallback) && this.status === PromiseStatus.REJECTED) {
console.log('task', promise);
rejectPromise(promise, this.status)
continue;
}
if(this.status === PromiseStatus.FULFILLED){
resolvePromise(promise, successCallback(this.data))
continue;
}
if(this.status === PromiseStatus.REJECTED){
rejectPromise(promise, errorCallback(this.error))
continue;
}
}
})
}
constructor(executor) {
try {
const resolve = (data) => {
resolvePromise(this, data)
}
const reject = (error) => {
rejectPromise(this, error)
}
executor(resolve, reject)
} catch (error) {
rejectPromise(this, error)
}
}
isThenable(fun) {
return fun && (typeof fun === 'function'
|| typeof fun === 'object') && typeof fun.then === 'function'
}
then(successCallback, errorCallback) {
const promise = new CustomPromise(() => { })
this.#onFulfilledCallbacks.push({
successCallback,
errorCallback,
promise
})
this._flushHandlers()
return promise
}
catch(errorCallback) {
return this.then(null, errorCallback)
}
}