const PROMISE_STATUS_PENDING = 'pending'
const PROMISE_STATUS_FULLFILLED = 'fullfilled'
const PROMISE_STATUS_REJECTED = 'rejected'
function executeFunWithCatcherError(exeFn, value, resolve, reject) {
try {
const result = exeFn(value)
resolve(result)
} catch (err) {
reject(err)
}
}
class MyPromise {
constructor(executor) {
this.status = PROMISE_STATUS_PENDING
this.value = undefined
this.reason = undefined
this.onFulfilledCallbacks = []
this.onRejectedCallbacks = []
const resolve = (value) => {
if (this.status === PROMISE_STATUS_PENDING) {
queueMicrotask(() => {
if (this.status !== PROMISE_STATUS_PENDING) return
this.status = PROMISE_STATUS_FULLFILLED
this.value = value
this.onFulfilledCallbacks.forEach(fn => {
fn(this.value)
})
})
}
}
const reject = (reason) => {
if (this.status === PROMISE_STATUS_PENDING) {
queueMicrotask(() => {
if (this.status !== PROMISE_STATUS_PENDING) return
this.status = PROMISE_STATUS_REJECTED
this.reason = reason
this.onRejectedCallbacks.forEach(fn => {
fn(this.reason)
})
})
}
}
executor(resolve, reject)
}
then(onfullfilled, onrejected) {
onrejected = onrejected || (err => {throw err})
onfullfilled = onfullfilled || (value => value)
return new MyPromise((resolve, reject) => {
if (this.status === PROMISE_STATUS_FULLFILLED && onfullfilled) {
executeFunWithCatcherError(onfullfilled, this.value, resolve, reject)
}
if (this.status === PROMISE_STATUS_REJECTED && onrejected) {
executeFunWithCatcherError(onrejected, this.reason, resolve, reject)
}
if (this.status === PROMISE_STATUS_PENDING) {
this.onFulfilledCallbacks.push(() => {
if (onfullfilled)executeFunWithCatcherError(onfullfilled, this.value, resolve, reject)
})
this.onRejectedCallbacks.push(() => {
if (onrejected)executeFunWithCatcherError(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, reject) => {
resolve(value)
})
}
static reject(reason) {
return new MyPromise((resolve, reject) => {
reject(reason)
})
}
static all(promises) {
return new MyPromise((resolve, reject) => {
let 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) => {
let values = []
promises.forEach(promise => {
promise.then(res => {
values.push({status: PROMISE_STATUS_FULLFILLED, value: res})
if (values.length === promises.length) {
resolve(values)
}
}).catch(err => {
values.push({status: PROMISE_STATUS_REJECTED, reason: err})
if (values.length === promises.length) {
resolve(values)
}
})
})
})
}
static race(promises) {
return new MyPromise((resolve, reject) => {
promises.forEach(promise => {
promise.then(res => {
resolve(res)
}, err => {
reject(err)
})
})
})
}
static any(promises) {
return new MyPromise((resolve, reject) => {
let reasons = []
promises.forEach(promise => {
promise.then(res => {
resolve(res)
}, err => {
reasons.push(err)
if (reasons.length === promises.length) {
reject(new AggregateError(reasons))
}
})
})
})
}
}
const p1 = new MyPromise((resolve, reject) =>{ setTimeout(() => {reject('111111')}, 1000) })
const p2 = new MyPromise((resolve, reject) =>{ setTimeout(() => {reject('22222222')}, 2000) })
const p3 = new MyPromise((resolve, reject) =>{ setTimeout(() => {reject('333333333')}, 3000) })
MyPromise.any([p1, p2, p3]).then(res => {
console.log('res', res)
}).catch(err => {
console.log('err', err)
})