const PENDING='pending'
const FULFILLED='fulfilled'
const REJECTED='rejected'
function isPromise(obj){
return !!(obj && typeof obj==='object' && obj.then)
}
function runMicroTask(executor){
if(process && process.nextTick){
process.nextTick(executor)
}else if(MutationObserver){
const p=document.createElement('p')
const observer=new MutationObserver(executor)
observer.observe(p,{
childList:true
})
p.innerHTML='1'
}else{
setTimeout(executor)
}
}
class MyPromise{
constructor(executor){
this._state=PENDING
this._value=undefined
this._handlers=[]
try{
executor(this._resolve.bind(this),this._reject.bind(this))
}catch(err){
this._reject(err)
}
}
_pushHandlers(executor,state,resolve,reject){
this._handlers.push({executor,state,resolve,reject})
}
then(onFulFilled,onRejected){
return new Promise((resolve,reject)=>{
this._pushHandlers(onFulFilled,FULFILLED,resolve,reject)
this._pushHandlers(onRejected,REJECTED,resolve,reject)
this._runHandler()
})
}
_runHandler(){
if(this._state===PENDING){
return;
}
while(this._handlers[0]){
this._runOneHandler(this._handlers[0])
this._handlers.shift()
}
}
_runOneHandler({executor,state,resolve,reject}){
runMicroTask(()=>{
if(this._state!==state){
return;
}else if(typeof executor !=='function'){
this._state===FULFILLED?resolve(this._value):reject(this._value)
}else{
try{
const res=executor(this._value)
if(isPromise(res)){
res.then(resolve,reject)
}else{
resolve(res)
}
}catch(err){
reject(err)
}
}
})
}
_resolve(data){
this._changeState(FULFILLED,data)
}
_reject(reason){
this._changeState(REJECTED,reason)
}
_changeState(newState,value){
if(this._state!==PENDING){
return;
}
this._state=newState
this._value=value
this._runHandler()
}
}