今天又复习了一下手写Promise和他的then方法,在手写的时候,对promise的原理和特性有了更深的了解,我就直接开写吧。
// 手写promise
// 首先定义promise的三个状态
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class myPromise {
// 定义私有化变量(前面加上#的变量),为状态,返回结果和多次调用then时存储数据的数组
#state = PENDING
#result = undefined
#handlers = []
constructor(fn) {
// 成功时返回resolve函数,同时改变promise状态,传入成功时的data
const resolve = (data) => {
this.#changeState(FULFILLED, data)
// 失败时返回resolve函数,同时改变promise状态,传入失败时的reason
}
const reject = (reason) => {
this.#changeState(REJECTED, reason)
}
// 调用fn函数时,使用try catch捕获错误,错误结果err传入reject
try {
fn(resolve, reject)
}
catch (err) {
reject(err)
}
}
// 捕获状态改变的方法
#changeState(state, result) {
// 如果是'pending',状态还没有改变
if (this.#state !== PENDING) return
// 状态改变了就传入改变的状态,并传入值
this.#state = state
this.#result = result
//调用run函数
this.#run()
}
// 把任务放进微任务队列(难点,选看)
#mircoTask(func) {
// node环境下的事件循环
if (typeof process === 'object' && typeof process.nextTick === 'function') {
process.nextTick(func)
}
// 浏览器环境下的事件循环
else if (typeof MutationObserver === 'function') {
const ob = new MutationObserver(func)
const textNode = document.createTextNode('1')
ob.observe(textNode, {
characterData: true
})
textNode.data = '2'
}
// 如果都不是,就使用setTimeout把任务放进微任务队列
else {
setTimeout(func, 0)
}
}
// 怕断传入的值是否是promise对象,promise对象只要符合:
// 1.是对象或者函数类型
// 2.有then方法
// 就可以断定这个值为promise对象
#isPromiseLike(value) {
if (value !== null && (typeof value === 'object' || typeof value === 'function')) {
return typeof value.then === 'function'
}
return false
}
// 把任务放进微任务队列
#runOne(callback, resolve, reject) {
this.#mircoTask(() => {
// 如果then里的值不是函数类型
if (typeof callback !== 'function') {
// 就判断状态是成功还是失败
const settled = this.#state === FULFILLED ? resolve : reject
settled(this.#result)
return
} else {
// 如果是函数类型,就用try,cathch捕获异常
try {
const data = callback(this.#result)
// 如果是promise对象,就接着调用then方法
if (this.#isPromiseLike(data)) {
data.then(resolve, reject)
} else {
// 否则就直接把data传入resolve
resolve(data)
}
}
// 错误直接传递err给reject
catch (err) {
reject(err)
}
}
})
}
// 通过while循环来链式调用then方法
#run() {
if (this.#state === PENDING) return
while (this.#handlers.length) {
// 解构出handlers中的这四个值
const { onFulfilled, onRejected, resolve, reject } = this.#handlers.shift()
// 来在微任务队列里(funOne函数)运行then方法里的函数或者值
if (this.#state === FULFILLED) {
this.#runOne(onFulfilled, resolve, reject)
} else {
this.#runOne(onRejected, resolve, reject)
}
}
}
// promise的then方法
then(onFulfilled, onRejected) {
// 返回一个新的promise对象
return new myPromise((resolve, reject) => {
// 把这几个都传入handlers数组
this.#handlers.push({
onFulfilled,
onRejected,
resolve,
reject
})
// 运行run函数
this.#run()
})
}
}