手写Promise,符合A+规范,A+规范只有一个构造函数,一个then方法,其他的不属于A+规范,而是属于ECMAScript规范
js
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
#state = PENDING
#result = undefined
// 这是一个后进前出的队列
#handler = []
constructor(executor) {
// resolve和reject两个函数可以放在MyPromise.prototype上,但是需要处理this指向问题
const resolve = (data) => {
this.#changeState(FULFILLED, data)
}
const reject = (errorReason) => {
this.#changeState(REJECTED, errorReason)
}
// try...catch只能捕获同步错误,无法捕获异步错误
try {
executor(resolve, reject)
} catch (e) {
reject(e)
}
}
#changeState(state, result) {
// promise的状态一旦改变就不能再改了
if (this.#state !== PENDING) return
this.#state = state
this.#result = result
}
// 判断是不是一个promise
#isPromiseLike(value) {
return (
value !== null &&
(typeof value === 'object' || typeof value === 'function') &&
typeof value.then === 'function'
)
}
// 参考vue源码的做法
// 将函数尽可能地放到微队列中去执行
#runMicoTask(func) {
if (typeof process === 'object' && typeof process.nextTick === 'function') {
// 在Node环境中模拟微队列
process.nextTick(func)
} else if (typeof MutationObserver === 'function') {
// 在浏览器环境中模拟微队列
const db = new MutationObserver(func)
const textNode = document.createTextNode('1')
db.observe(textNode, {
characterData: true,
})
textNode.data = '2'
} else {
setTimeout(func, 0)
}
}
#runOne(callback, resolve, reject) {
this.#runMicoTask(() => {
if (typeof callback !== 'function') {
const settled = this.#state === FULFILLED ? resolve : reject
settled(this.#result)
return
}
try {
const data = callback(this.#result)
if (this.#isPromiseLike(data)) {
data.then(resolve, reject)
} else {
resolve(data)
}
} catch (err) {
reject(err)
}
})
}
// 什么时候执行resolve和reject?
// 1. 传递的参数不是函数,promise的状态穿透
// 2. 传递的参数是一个函数
// 3. 返回结果是Promise
#run() {
if (this.#state === PENDING) return
while (this.#handler.length) {
const { onFulfilled, onRejected, resolve, reject } = this.#handler.shift()
if (this.#state === FULFILLED) {
this.#runOne(onFulfilled, resolve, reject)
} else {
this.#runOne(onRejected, resolve, reject)
}
}
}
// Promise.prototype.then方法返回一个Promise
// 什么执行onFulfilled,什么时候执行onRejected
then(onFulfilled, onRejected) {
return new MyPromise((resolve, reject) => {
this.#handler.push({
onFulfilled,
onRejected,
resolve,
reject,
})
this.#run()
})
}
}