手写Promise

61 阅读1分钟
 class MyPromise{
    static FULLFILLED = "成功"
    static REJECTED = "拒绝"
    static PENDING = "待定"
    constructor(executor){
        this.status = MyPromise.PENDING
        this.value = undefined
        this.reason = undefined
        this.successCallbacks = []
        this.failCallbacks = []
        try{
            executor(this.resolve,this.reject)
        }catch(e){
            this.reject(e.message)
        }
    }
    resolve = (value)=>{
        if(this.status !== MyPromise.PENDING) return
        this.status = MyPromise.FULLFILLED
        this.value = value
        while(this.successCallbacks.length){
            this.successCallbacks.shift()()
        }
    }
    reject = (reason)=>{
        if(this.status !== MyPromise.PENDING) return
        this.status = MyPromise.REJECTED
        this.reason = reason
        while(this.failCallbacks.length){
            this.failCallbacks.shift()()
        }
    }
    then = (successCallback, failCallback)=>{
        let p1 = new MyPromise((resolve,reject)=>{
            const resolvePromise = (promise,value,resolve,reject)=> {
                // console.log('promise,value,resolve,reject', promise,value,resolve,reject)
                if(promise === p1){
                    throw new TypeError('chaining cycle detected for promise')
                }
                if(value instanceof MyPromise){
                    value.then(resolve,reject)
                }else{
                    resolve(value)
                }
            }
            if(this.status === MyPromise.FULLFILLED){
                setTimeout(()=>{
                    try{
                        let value = successCallback(this.value)
                        resolvePromise(p1,value,resolve,reject)
                    }catch(e){
                        reject(e.message)
                    }
                },0)
            }else if(this.status === MyPromise.REJECTED){
                setTimeout(()=>{
                    try{
                        let value = failCallback(this.reason)
                        resolvePromise(p1,value,resolve,reject)
                    }catch(e){
                        // console.log(e)
                        reject(e.message)
                    }
                },0)
            }else if(this.status === MyPromise.PENDING){
                this.successCallbacks.push(()=>{
                    setTimeout(()=>{
                        try{
                            let value = successCallback(this.value)
                            resolvePromise(p1,value,resolve,reject)
                        }catch(e){
                            reject(e.message)
                        }
                    },0)
                })
                this.failCallbacks.push(()=>{
                    setTimeout(()=>{
                        try{
                            let value = failCallback(this.reason)
                            resolvePromise(p1,value,resolve,reject)
                        }catch(e){
                            reject(e.message)
                        }
                    },0)
                })
            }
        })
        return p1
    }
    finally = (cb)=>{
        return this.then((value)=>{
            return MyPromise.resolve(cb()).then(()=>value)
        },reason=>{
            return MyPromise.resolve(cb()).then(()=>{throw reason})
        })
    }
    catch(failCallback){
        return this.then(undefined,failCallback)
    }
    static resolve = (value)=>{
        if(value instanceof MyPromise) return value
        return new Promise(resolve=>resolve(value))
    }
    static all = (arr)=>{
        let result = []
        let index = 0
        return new MyPromise((resolve,reject)=>{
            const addData = (key,value)=>{
                index++
                result[key] = value
                if(index = arr.length){
                    resolve(result)
                }
            }
            for(let i = 0; i < arr.length; i++){
                if(arr[i] instanceof MyPromise){
                    arr[i].then((res)=>{
                        addData(i,res)
                    },err => {
                        reject(err)
                    }) 
                }else {
                    addData(i,arr[i])
                }
                
            }
        })
    }
    
}