const PENDING='pending';
const FULFILLED='fulfilled'
const REJECTED='rejected'
class MyPromise{
constructor(executer){
try{
executer(this.resolve,this.reject)
}
catch(e){
this.reject(e)
}
}
value=undefined
reason=undefined
status=PENDING
successCallbacks=[]
failCallbacks=[]
static resolve(v){
if(v instanceof MyPromise){
return v;
}
return new MyPromise(resolve=>resolve(v))
}
resolve=v=>{
if(this.status!==PENDING)return;
this.value=v;
this.status=FULFILLED;
while(this.successCallbacks.length){
successCallbacks.shift()();
}
}
reject=e=>{
if(this.status!==PENDING)return;
this.reason=e;
this.status=REJECTED;
while(this.failCallbacks.length){
failCallbacks.shift()();
}
}
then(successCallback,failCallback){
successCallback=typeof successCallback==='function'?successCallback:v=>v;
failCallback=typeof failCallback==='funtion'?failCallback:e=>{throw e};
const subPromise = new MyPromise((resolve,reject)=>{
switch(this.status){
case FULFILLED:{
queueMicrotask(()=>{
try{
const x=successCallback(this.value);
resolvePromise(subPromise,x,resolve,reject);
}
catch(e){
reject(e)
}
})
break;
}
case REJECTED:{
queueMicrotask(()=>{
try{
const x=failCallback(this.reason);
resolvePromise(subPromise,x,resolve,reject);
}
catch(e){
reject(e)
}
})
break;
}
case PENDING:{
successCallbacks.push(()=>{
queueMicrotask(()=>{
try{
const x=successCallback(this.value);
resolvePromise(subPromise,x,resolve,reject);
}
catch(e){
reject(e)
}
})
})
failCallbacks.push(()=>{
queueMicrotask(()=>{
try{
const x=failCallback(this.reason);
resolvePromise(subPromise,x,resolve,reject);
}
catch(e){
reject(e)
}
})
})
break;
}
}
})
return subPromise;
}
catch(onRejected){
this.then(null,onRejected)
}
finally(callback){
return this.then(
v=>MyPromise.resolve(callback()).then(()=>v),
e=>MyPromise.resolve(callback()).then(()=>{throw e}),
)
}
}
function resolvePromise(subPromise,x,resolve,reject){
if(subPromise===x){
reject(new typeError('Chaining caycle detected for promise #<Promise>'))
}
else if(x instanceof MyPromise){
return x
}
else {
reslove(x)
}
}