const PENDING = "pending"
const FULFILLED = "fulfilled"
const REJECTED = "rejected"
function resolvePromise(promise2, x, resolve, reject) {
if (promise2 === x) {
return reject(
new TypeError("Chaining cycle detected for promise
)
}
let called = false
if ((typeof x === "object" && typeof x !== null) || typeof x === "function") {
try {
const then = x.then
if (typeof then === "function") {
then.call(
x,
(y) => {
if (called) return
called = true
resolvePromise(x, y, resolve, reject)
},
(r) => {
if (called) return
called = true
reject(r)
}
)
} else {
resolve(x)
}
} catch (error) {
if (called) return
called = true
reject(error)
}
} else {
resolve(x)
}
}
class MyPromise {
constructor(executor) {
this.status = PENDING
this.value = undefined
this.reason = undefined
this.onFulfiledCallbacks = []
this.onRejectedCallbacks = []
const resolve = (value) => {
if (this.status === PENDING) {
this.status = FULFILLED
this.value = value
this.onFulfiledCallbacks.map((fn) => fn())
}
}
const reject = (reason) => {
if (this.status === PENDING) {
this.status = REJECTED
this.reason = reason
this.onRejectedCallbacks.map((fn) => fn())
}
}
try {
executor(resolve, reject)
} catch (error) {
reject(error)
}
}
then(onFulfiled, onRejected) {
onFulfiled =
typeof onFulfiled === "function" ? onFulfiled : (value) => value
onRejected =
typeof onRejected === "function"
? onRejected
: (reason) => {
throw reason
}
const promise2 = new MyPromise((resolve, reject) => {
if (this.status === FULFILLED) {
setTimeout(() => {
try {
let x = onFulfiled(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
}, 0)
}
if (this.status === REJECTED) {
setTimeout(() => {
try {
let x = onRejected(this.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
}, 0)
}
if (this.status === PENDING) {
this.onFulfiledCallbacks.push(() => {
try {
let x = onFulfiled(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
this.onRejectedCallbacks.push(() => {
try {
let x = onRejected(this.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
}
})
return promise2
}
catch(errorCallback) {
this.then(null, errorCallback)
}
}
module.exports = MyPromise