function MyPromise(fn) {
let value = null
let state = "pending"
let callbacks = []
this.then = function (onFulfilled, onRejected) {
return new MyPromise((resolve, reject) => {
handle({
onFulfilled: onFulfilled || null,
onRejected: onRejected || null,
resolve: resolve,
reject,
})
})
}
this.catch = function (onError) {
return this.then(null, onError)
}
this.finally = function (onDone) {
this.then(onDone, onDone)
}
function handle(cb) {
if (state === "pending") {
callbacks.push(cb)
return
}
let callback = state === "fulfilled" ? cb.onFulfilled : cb.onRejected
let ret
if (callback === null) {
cb = state === "fulfilled" ? callback.resolve : callback.reject
cb(value)
return
}
try {
ret = callback(value)
cb.resolve(ret)
} catch (e) {
cb.reject(e)
}
}
resolve = function (newValue) {
if (
newValue &&
(typeof newValue === "object" || typeof newValue === "function")
) {
var then = newValue.then
if (typeof then === "function") {
then.call(newValue, resolve)
return
}
}
value = newValue
state = "fulfilled"
execute()
}
reject = function (reason) {
state = "rejected"
value = reason
execute()
}
execute = function () {
setTimeout(() => {
// 保证执行cb时候,已经全部加入callbacks队列了
callbacks.forEach((cb) => {
handle(cb)
})
}, 0)
}
fn(resolve, reject)
}
MyPromise.all = function (promises) {
return new MyPromise((resolve, reject) => {
// 参数判断
if (!Array.isArray(promises)) {
throw new TypeError("promises must be an array")
}
let result = []
let count = 0
promises.forEach((promise, index) => {
promise.then(
(res) => {
result[index] = res
count++
count === promises.length && resolve(result)
},
(err) => {
reject(err)
}
)
})
})
}
MyPromise.race = function (promises) {
return new MyPromise((resolve, reject) => {
promises.forEach((promise) => {
promise.then(resolve, reject)
})
})
}
MyPromise.allSettled = function (values) {
let promises = [].slice.call(values)
return new MyPromise((resolve, reject) => {
let result = [],
count = 0
promises.forEach((promise) => {
promise.then((value) => {
result.push({ status: "fulfilled", value })
})
.catch((err) => {
result.push({ status: "rejected", value: err })
})
.finally(() => {
if (++count === promise.length) {
resolve(result)
}
})
})
})
}