class MyPromise {
static PENDING = 'PENDING'
static FULFILLED = 'FULFILLED'
static REJECTED = 'REJECTED'
status = MyPromise.PENDING
callbacks = []
value = null
constructor(executor) {
try {
executor(this.resolve, this.reject)
} catch (err) {
this.reject(err)
}
}
resolve(res) {
if(this.status === MyPromise.PENDING) {
this.value = res
this.status = MyPromise.FULFILLED
queueMicrotask(() => {
this.callbacks.forEach(({fulfilled}) => {
fulfilled(res)
})
})
}
}
reject(err) {
if(this.status === MyPromise.REJECTED) {
this.status = MyPromise.REJECTED
this.value = err
queueMicrotask(() => {
this.callbacks.forEach(({rejected}) => {
rejected(err)
})
})
}
}
then(fulfilled, rejected) {
if(typeof fulfilled !== 'function') fulfilled = (res) => res
if(typeof rejected !== 'function') rejected = (err) => err
const promise = new MyPromise((resolve, reject) => {
if(this.status === MyPromise.PENDING) {
this.callbacks.push({
fulfilled: (res) => this.parse(promise, fulfilled(res), resolve, reject),
rejected: (err) => this.parse(promise, rejected, resolve, reject)
})
} else if(this.status === MyPromise.FULFILLED) {
queueMicrotask(() => {
this.parse(promise, fulfilled(this.value), resolve, reject)
})
} else {
queueMicrotask(() => {
this.parse(promise, rejected(this.value), resolve, reject)
})
}
})
return promise
}
parse(promise, result, resolve, reject) {
if(promise === result) throw new Error('circular promise')
try {
if(result instanceof MyPromise) {
result.then(resolve, reject)
} else {
resolve(result)
}
} catch (err) {
reject(err)
}
}
}