手写Promise

54 阅读1分钟
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()
    }
}