Promise A+ 规范
const PENDING = "pending"
const FULFILLED = "fulfilled"
const REJECTED = "rejected"
function enterMicroQueue(callack) {
if (typeof callack !== "function") return
if (typeof MutationObserver !== "undefined") {
const div = document.createElement("div")
const observer = new MutationObserver(callack)
observer.observe(div, { childList: true })
div.innerHTML = "1"
} else if (process && process.nextTick) {
process.nextTick(callack)
} else {
setTimeout(callack, 0)
}
}
function isPromise(obj) {
return !!(obj && typeof obj === "object" && typeof obj.then === "function")
}
class MyPromise {
#handlers = []
constructor(executor) {
this._state = PENDING
this._value = undefined
try {
if (typeof executor === "function") {
executor(this.#resolve.bind(this), this.#reject.bind(this))
}
} catch (error) {
this.#changeState(REJECTED, error)
}
}
#changeState(newState, value) {
if (this._state !== PENDING) return
if (isPromise(value)) {
value.then(this.#resolve.bind(this), this.#reject.bind(this))
return
}
Object.defineProperties(this, {
_state: {
configurable: false,
enumerable: true,
value: newState,
writable: false,
},
_value: {
configurable: false,
enumerable: true,
value: value,
writable: false,
},
})
this.#runHandlers()
}
then(onFulfilled, onRejected) {
return new MyPromise((resolve, reject) => {
this.#collectHandlers(onFulfilled, FULFILLED, resolve, reject)
this.#collectHandlers(onRejected, REJECTED, resolve, reject)
this.#runHandlers()
})
}
#collectHandlers(executor, state, resolve, reject) {
this.#handlers.push({
executor,
state,
resolve,
reject,
})
}
#runHandlers() {
if (this._state === PENDING) return
while (this.#handlers[0]) {
this.#runOneHandler(this.#handlers[0])
this.#handlers.shift()
}
}
#runOneHandler({ state, executor, resolve, reject }) {
enterMicroQueue(() => {
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)
}
})
}
#resolve(data) {
this.#changeState(FULFILLED, data)
}
#reject(reason) {
this.#changeState(REJECTED, reason)
}
}
catch()
catch(onRejected){
return this.then(null, onRejected)
}
finally()
finally(onSettled){
return this.then((data) => {
onSettled()
return data
}, (error) => {
onSettled()
throw error;
})
}
resolve()
static resolve(data) {
if (data instanceof MyPromise) return data
return new MyPromise((resolve, reject) => {
if (isPromise(data)) {
data.then(resolve, reject)
} else {
resolve(data)
}
})
}
reject()
static reject(reason) {
return new MyPromise((resolve, reject) => {
reject(reason)
})
}
all()
static all(proms) {
return new MyPromise((resolve, reject) => {
try {
const resultData = []
let count = 0
let fulfilledCount = 0
for (const p of proms) {
let i = count
count++
MyPromise.resolve(p).then((data) => {
fulfilledCount++
resultData[i] = data
if (fulfilledCount === count) resolve(resultData)
}, reject)
}
if (!count) resolve(resultData)
} catch (error) {
reject(error)
}
})
}
allSettled()
static allSettled(proms) {
const ps = []
for (const p of proms) {
ps.push(
MyPromise.resolve(p).then(
(value) => ({
states: FULFILLED,
value,
}),
(reason) => ({
states: REJECTED,
reason,
})
)
)
}
return MyPromise.all(ps)
}
rance()
static race(proms) {
return new MyPromise((resolve, reject) => {
for (const p of proms) {
MyPromise.resolve(p).then(resolve, reject)
}
})
}
any()