手写 Promise A+ 规范
首先 基于 Promise 的状态我们定义几个常见的常量
js
// Promise 有两个阶段, 三种状态
const PENDING = 'pending' //待定状态
const FULFILLED = 'fulfilled' //已兑现 状态
const REJECTED = 'rejected' //已拒绝 状态
const SETTLED = 'settled' // 已决阶段
const UNSETTLED = 'unsettled' // 未决阶段
注意: 如果一个 Promise 已经被兑现或拒绝,即不再处于待定状态,那么则称之为已敲定(settled)
。这意味着该 Promise 已经敲定(settled),或为了匹配另一个 Promise 的最终状态而被"锁定(lock-in)",进一步解决或拒绝它都没有影响
。
基于 Promise 是 通过 new 关键字创建的, 创建自己的 Promise 类 RPromise
js
class RPromise {
/**
* Promise 构造函数
* @param {Function} executor 任务执行器
*/
constructor(executor) {
this._state = PENDING //状态
this._value = undefined // 返回包装的值
this._handlers = [] //处理函数任务队列
try {
executor(this._resolve.bind(this), this._reject.bind(this))
} catch (error) {
this._reject(error)
console.log('Error:', error)
}
}
}
我们先实现最简单的如何改变 Promise 的状态
js
/**
* 设置任务到 fulfilled
*/
_resolve(data) {
if (this._state === PENDING) {
this._changeState(FULFILLED, data)
}
}
_changeState(newState, value) {
if (this._state !== PENDING) return
this._state = newState
this._value = value
this._runHandlers()
}
/**
* 设置任务到 rejected
*/
_reject(reason) {
if (this._state === PENDING) {
this._changeState(REJECTED, reason)
}
}
接下来 基于 Promise A+ 规范来实现 then 方法
js
/**
* Promise A+ .then 方法
* @param {Function} onFulfilled
* @param {Function} onRejected
*/
then(onFulfilled, onRejected) {
// onFulfilled =
// typeof onFulfilled === 'function' ? onFulfilled : () => onFulfilled
// onRejected =
// typeof onRejected === 'function'
// ? onRejected
// : () => {
// throw onRejected
// }
return new RPromise((resolve, reject) => {
this._pushHandles(onFulfilled, FULFILLED, resolve, reject)
this._pushHandles(onRejected, REJECTED, resolve, reject)
this._runHandlers() //执行队列
})
}
/**
* 根据实际情况,执行队列
*/
_runHandlers() {
if (this._state === PENDING) return
if (!Array.isArray(this._handlers)) return
while (this._handlers.length) {
const handler = this._handlers.shift()
this._runOnceHandler(handler)
}
}
/**
* 向处理队列中添加一个函数
* @param {Function} executor
* @param {String} state
* @param {Function} resolve 让 then 函数 返回的 Promise 成功
* @param {Function} reject 让 then 函数返回的 Promise 失败
*/
_pushHandles(executor, state, resolve, reject) {
if (executor && typeof executor === 'function') {
this._handlers.push({
executor,
state,
resolve,
reject,
})
}
}
/**
* 判断是否为 Promise
* @param {*} obj
* @returns
*/
function isPromise(obj) {
if (obj instanceof Promise) return true
return !!(obj && typeof obj === 'object' && typeof obj.then === 'function')
}
/**
* handler 处理函数
* @param {*} handler
*/
_runOnceHandler(handler) {
const { executor, state, resolve, reject } = handler
runMicroTask(() => {
if (this._state !== state) {
// 状态不一致,不处理
return
}
if (typeof executor !== 'function') {
this._state === FULFILLED ? resolve(this._value) : reject(this._value)
return
}
try {
const result = executor(this._value)
if (isPromise(result)) {
result.then(resolve, reject)
} else {
resolve(result)
}
} catch (error) {
reject(error)
console.log('Error:', error)
}
})
}
我们知道 promise.then 方法的回调函数是微任务队列执行,通过写一个 创建微任务队列函数来创建微任务队列
js
/**
* 运行一个微任务, 把传递的函数放到微任务之中
* @param {Function} callback
*/
function runMicroTask(callback) {
// 通过 process 来判断 node 环境, 使用 process.nextTick 实现微队列
if (process && process.nextTick) {
process.nextTick(callback)
} else if (MutationObserver) {
// 实现浏览器下的微队列
const virElement = document.createElement('p')
const observer = new MutationObserver(callback)
observer.observe(virElement, {
childList: true,
attributes: true,
})
virElement.innerHTML = 'unknown'
} else {
setTimeout(() => {
try {
callback()
} catch (e) {}
}, 0)
}
}
Promise 的 catch 方法实现
js
/**
* Promise catch 方法
* @param {*} onRejected
*/
catch(onRejected) {
return this.then(null, onRejected)
}
promise finally 方法实现
js
/**
* finally 无论是成功或失败都会运行
* @param {*} callback
*/
finally(callback) {
return this.then(
(data) => {
callback()
return data
},
(reason) => {
callback()
throw reason
}
)
}
promise 静态方法
resolve 方法
Promise.resolve()
静态方法将给定的值转换为一个 Promise
。如果该值本身就是一个 Promise,那么该 Promise 将被返回;如果该值是一个 thenable 对象,Promise.resolve()
将调用其 then()
方法及其两个回调函数;否则,返回的 Promise 将会以该值兑现。
该函数将嵌套的类 Promise 对象(例如,一个将被兑现为另一个 Promise 对象的 Promise 对象)展平,转化为单个 Promise 对象,其兑现值为一个非 thenable 值。
js
/**
*
* @param {*} value
* @returns
*
* 1. 传递的 data 本身就是 Es6 的 Promise
* 2. 传递的 data 是 PromiseLike (Promise A+),返回一个 新的Promise
*/
static resolve(value) {
// 如果该值本身就是一个 Promise(用 instanceof 判断)
if (value instanceof RPromise || value instanceof Promise) {
return value
}
return new RPromise((resolve, reject) => {
//如果是一个类 Promise 对象
if (isPromise(value)) {
value.then(resolve, reject)
} else {
//如果为值的形式,包一个 resolve
resolve(value)
}
})
}
reject 方法
Promise.reject()
静态方法返回一个已拒绝(rejected)的 Promise
对象,拒绝原因为给定的参数。
js
/**
*
* @param {*} reason 传入失败的原因
* @returns
*
*/
static reject(reason) {
return new RPromise((_, reject) => {
reject(reason)
})
}
注意: 下文中的所有实现都没有使用 length 属性,是因为 如果传入的是一个 iterator 迭代对象
而非数组 会没有 length 属性
Promise.all 方法
Promise.all()
静态方法接受一个 Promise 可迭代对象作为输入,并返回一个 Promise
。当所有输入的 Promise 都被兑现时,返回的 Promise 也将被兑现(即使传入的是一个空的可迭代对象),并返回一个包含所有兑现值的数组
。
js
/**
*
* @param {itorator} promiseArrays
*/
RPromise.all = function (promiseArrays) {
return new RPromise((resolve, reject) => {
try {
const results = []
let count = 0
let fulfilledCount = 0
for (const promiseItem of promiseArrays) {
let index = count
count++
RPromise.resolve(promiseItem).then((data) => {
fulfilledCount++
results[index] = data
if (fulfilledCount === count) {
// TODO:此时 promiseArr 已全部完成
resolve(results)
}
}, reject)
}
if (count === 0) resolve(results)
} catch (error) {
reject(error)
}
})
}
promise.allSettled 方法
Promise.allSettled()
静态方法将一个 Promise 可迭代对象作为输入,并返回一个单独的 Promise
。当所有输入的 Promise 都已敲定时(包括传入空的可迭代对象时),返回的 Promise 将被兑现,并带有描述每个 Promise 结果的对象数组。
js
RPromise.allSettled = function (promiseArrays) {
return new RPromise((resolve, reject) => {
try {
const ps = []
for (const promiseItem of promiseArrays) {
ps.push(
RPromise.resolve(promiseItem).then(
(value) => ({ status: FULFILLED, value: value }),
(reason) => ({ status: REJECTED, reason: reason })
)
)
}
return RPromise.all(ps)
} catch (error) {
reject(error)
}
})
promise.race 方法
Promise.race()
静态方法接受一个 promise 可迭代对象作为输入,并返回一个 Promise
。这个返回的 promise 会随着第一个 promise 的敲定而敲定。
js
RPromise.race = function (promiseArrays) {
return new RPromise((resolve, reject) => {
try {
for (const promiseItem of promiseArrays) {
RPromise.resolve(promiseItem).then(resolve, reject)
}
} catch (error) {
reject(error)
}
})
}
promise.any 方法
Promise.any()
静态方法将一个 Promise 可迭代对象作为输入,并返回一个 Promise
。当输入的任何一个 Promise 兑现时,这个返回的 Promise 将会兑现,并返回第一个兑现的值。当所有输入 Promise 都被拒绝(包括传递了空的可迭代对象)时,它会以一个包含拒绝原因数组的 AggregateError
拒绝。
js
RPromise.any = function (promiseArrays) {
return new RPromise((resolve, reject) => {
try {
const reasonResult = []
let count = 0
let rejectCount = 0
for (const promiseItem of promiseArrays) {
count++
RPromise.resolve(promiseItem).then(resolve, (reason) => {
reasonResult[rejectCount] = new Error(reason)
rejectCount++
if (rejectCount === count) {
reject(new AggregateError(reasonResult))
}
})
}
} catch (error) {
reject(error)
}
})
}
最后使用 CommonJs 的导出 module.exports 导出我们自己的 Promise
js
module.exports = RPromise