class MyPromise {
constructor(executor) {
this._status = "pending"
this._value = undefined
this._error = undefined
this._resolveQueue = []
this._rejectQueue = []
const resolve = (value) => {
if (this._status === "pending") {
this._status = "fulfilled"
this._value = value
while (this._resolveQueue.length) {
const callback = this._resolveQueue.shift()
callback(this._value)
}
}
}
const reject = (error) => {
if (this._status === "pending") {
this._status = "rejected"
this._error = error
while (this._rejectQueue.length) {
const callback = this._rejectQueue.shift()
callback(this._error)
}
}
}
try {
executor(resolve, reject)
} catch (error) {
reject(error)
}
}
then(onFulfilled, onRejected) {
onFulfilled =
typeof onFulfilled === "function" ? onFulfilled : (value) => value
onRejected =
typeof onRejected === "function"
? onRejected
: (error) => {
throw error
}
return new MyPromise((resolve, reject) => {
const resolveFn = (value) => {
try {
const x = onFulfilled(value)
x instanceof MyPromise ? x.then(resolve, reject) : resolve(x)
} catch (error) {
reject(error)
}
}
const rejectFn = (error) => {
try {
const x = onRejected(error)
x instanceof MyPromise ? x.then(resolve, reject) : resolve(x)
} catch (error) {
reject(error)
}
}
if (this._status === "pending") {
this._resolveQueue.push(resolveFn)
this._rejectQueue.push(rejectFn)
} else if (this._status === "fulfilled") {
resolveFn(this._value)
} else if (this._status === "rejected") {
rejectFn(this._error)
}
})
}
catch(onRejected) {
return this.then(null, onRejected)
}
finally(onFinally) {
return this.then(
(value) => MyPromise.resolve(onFinally()).then(() => value),
(error) =>
MyPromise.resolve(onFinally()).then(() => {
throw error
})
)
}
static resolve(value) {
return new MyPromise((resolve) => {
resolve(value)
})
}
static reject(error) {
return new MyPromise((_, reject) => {
reject(error)
})
}
static all(promises) {
const results = []
let count = 0
return new MyPromise((resolve, reject) => {
for (let i = 0
MyPromise.resolve(promises[i]).then(
(value) => {
results[i] = value
count++
if (count === promises.length) {
resolve(results)
}
},
(error) => {
reject(error)
}
)
}
})
}
static race(promises) {
return new MyPromise((resolve, reject) => {
for (let i = 0
MyPromise.resolve(promises[i])
.then((value) => {
resolve(value)
})
.catch((error) => {
reject(error)
})
}
})
}
}