const PROMISE_STATUS_PENDING = 'pending'
const PROMISE_STATUS_FULFILLED = 'fulfilled'
const PROMISE_STATUS_REJECTED = 'rejected'
function execFunctionWithCatchError(exec, value, resolve, reject) {
try {
const result = exec(value)
resolve(result)
} catch (err) {
reject(err)
}
}
class MyPromise {
constructor(executor) {
this.status = PROMISE_STATUS_PENDING
this.value = undefined
this.reason = undefined
this.onFulfilledFns = []
this.onRejectedFns = []
const resolve = (value) => {
if (this.status === PROMISE_STATUS_PENDING) {
queueMicrotask(() => {
if (this.status !== PROMISE_STATUS_PENDING) return
this.value = value
this.status = PROMISE_STATUS_FULFILLED
this.onFulfilledFns.forEach(fn => {
fn(this.value)
})
})
}
}
const reject = (reason) => {
if (this.status === PROMISE_STATUS_PENDING) {
queueMicrotask(() => {
if (this.status !== PROMISE_STATUS_PENDING) return
this.reason = reason
this.status = PROMISE_STATUS_REJECTED
this.onRejectedFns.forEach(fn => {
fn(this.reason)
})
})
}
}
try {
executor(resolve, reject)
} catch (err) {
reject(err)
}
}
then(onFulfilled, onRejected) {
const defaultOnRejected = err => { throw err }
onRejected = onRejected ?? defaultOnRejected
const defaultOnFulfilled = value => { return value }
onFulfilled = onFulfilled ?? defaultOnFulfilled
return new MyPromise((resolve, reject) => {
if (this.status === PROMISE_STATUS_PENDING) {
this.onFulfilledFns.push(() => {
execFunctionWithCatchError(onFulfilled, this.value, resolve, reject)
})
this.onRejectedFns.push(() => {
execFunctionWithCatchError(onRejected, this.reason, resolve, reject)
})
}
if (this.status === PROMISE_STATUS_FULFILLED) {
execFunctionWithCatchError(onFulfilled, this.value, resolve, reject)
}
if (this.status === PROMISE_STATUS_REJECTED) {
execFunctionWithCatchError(onRejected, this.reason, resolve, reject)
}
})
}
catch(onRejected) {
return this.then(undefined, onRejected)
}
finally(onFinally) {
this.then(() => {
onFinally()
}, () => {
onFinally()
})
}
static resolve(value) {
return new MyPromise((resolve) => resolve(value))
}
static reject(reason) {
return new MyPromise((resolve, reject) => reject(reason))
}
static all(promises) {
// 问题关键: 什么时候执行resolve 什么时候执行reject
return new MyPromise((resolve, reject) => {
const values = []
promises.forEach((promise) => {
promise.then(res => {
values.push(res)
if (values.length === promises.length) {
resolve(values)
}
}, err => {
reject(err)
})
})
})
}
static allSettled(promises) {
return new MyPromise((resolve, reject) => {
const values = []
promises.forEach(promise => {
promise.then(res => {
values.push({ status: PROMISE_STATUS_FULFILLED, value: res })
if (values.length === promises.length) {
resolve(values)
}
}, err => {
values.push({ status: PROMISE_STATUS_REJECTED, value: err })
if (values.length === promises.length) {
resolve(values)
}
})
})
})
}
static race(promises) {
return new MyPromise((resolve, reject) => {
promises.forEach(promise => {
promise.then(resolve, reject)
})
})
}
static any(promises) {
return new MyPromise((resolve, reject) => {
const reasons = []
promises.forEach(promise => {
promise.then(resolve, err => {
reasons.push(err)
if (reasons.length === promises.length) {
reject(new AggregateError(reasons))
}
})
})
})
}
}
const promise1 = new MyPromise((resolve, reject) => {
setTimeout(() => { reject(111) }, 1000)
})
const promise2 = new MyPromise((resolve, reject) => {
setTimeout(() => { reject(222) }, 2000)
})
const promise3 = new MyPromise((resolve, reject) => {
setTimeout(() => { reject(333) }, 3000)
})
MyPromise.any([promise1, promise2, promise3]).then(res => {
console.log("res: ", res)
}).catch(err => {
console.log("err: ", err)
})
手写Promise最终版
©著作权归作者所有,转载或内容合作请联系作者
- 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
- 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
- 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
推荐阅读更多精彩内容
- 整体和NC开发中间表一样。 这个只是日志表的设计与创建 ********数据库表设计********** --创...
- 在做 Cocos Creator H5 联机小游戏的时候, 想用 Socket.io 来进行实时通信, 一阵搜...