const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
constructor(executor) {
try {
executor(this.resolve, this.reject)
} catch (error) {
this.reject(error)
}
}
status = PENDING
value = null
reason = null
successCallback = []
failCallback = []
resolve = (value) => {
if (this.status === PENDING) {
this.status = FULFILLED
this.value = value
this.successCallback.forEach(fn => fn())
}
}
reject = (reason) => {
if (this.status === PENDING) {
this.status = REJECTED
this.reason = reason
this.failCallback.forEach(fn => fn())
}
}
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (value => value)
onRejected = typeof onRejected === 'function' ? onRejected : (err => { throw err })
let p = new MyPromise((resolve, reject) => {
const resolveMyPromise = (callback, result) => {
queueMicrotask(() => {
try {
const x = callback(result)
if (x === p) {
throw new TypeError('Chaining cycle detected for promise #<Promise>')
} else if (x instanceof MyPromise) {
x.then(resolve, reject)
} else {
resolve(x)
}
} catch (error) {
reject(error)
throw new TypeError(error)
}
})
}
if (this.status === FULFILLED) {
resolveMyPromise(onFulfilled, this.value)
} else if (this.status === REJECTED) {
resolveMyPromise(onRejected, this.reason)
} else {
this.successCallback.push(() => {
resolveMyPromise(onFulfilled, this.value)
})
this.failCallback.push(() => {
resolveMyPromise(onRejected, this.reason)
})
}
})
return p
}
catch(failCallback) {
return this.then(undefined, failCallback)
}
static all(promises){
return new MyPromise((resolve,reject)=>{
let arr=[]
let count=0
function addArr(value,index){
arr[index]=value
count++
if(count==promises.length){
resolve(arr)
}
}
promises.forEach((promise,index)=>{
if(promise instanceof MyPromise){
promise.then(res=>{
addArr(res,index)
},err=>{
reject(err)
})
}else{
addArr(promise,index)
}
})
})
}
static any(promises){
return new MyPromise((resolve,reject)=>{
let count=0
promises.forEach(promise=>{
if(promise instanceof MyPromise){
promise.then(res=>{
resolve(res)
},err=>{
count++
if(count==promises.length){
reject('all reject')
}
})
}else{
resolve(promise)
}
})
})
}
static race(promises){
return new MyPromise((resolve,reject)=>{
promises.forEach(promise=>{
if(promise instanceof MyPromise){
promise.then(res=>{
resolve(res)
},err=>{
reject(err)
})
}else{
resolve(promise)
}
})
})
}
}