模擬Promise的功能

菜鳥小於 發表於 2022-11-30

模擬Promise的功能,  按照下面的步驟,一步一步

1. 新建是個建構函式

2. 傳入一個可執行函式 函式的入參第一個為 fullFill函式 第二個為 reject函式; 函式立即執行, 引數函式非同步執行
3. 狀態一旦更改就不可以變更 只能 pending => fulfilled 或者 pending => rejected
4. then 的時候要處理入參的情況 successCallback 和failCallback 均可能為非函式

  • 預設的 failCallback 一定要將異常丟擲, 這樣下一個promise便可將其捕獲 異常冒泡的目的

5. then 中執行回撥的時候要捕獲異常 將其傳給下一個promise

  • 如果promise狀態未變更 則將回撥方法新增到對應佇列中
  • 如果promise狀態已經變更 需要非同步處理成功或者失敗回撥
  • 因為可能出現 回撥結果和當前then返回的Promise一致 從而導致死迴圈問題

6. catch只是then的一種特殊的寫法 方便理解和使用
7. finally 特點

  1. 不過resolve或者reject都會執行
  2. 回撥沒有引數
  3. 返回一個Promise 且值可以穿透到下一個then或者catch

8. Promise.resolve, Promise.reject 根據其引數返回對應的值 或者狀態的Promise即可
9. Proise.all 特點

  1. 返回一個Promise
  2. 入參是陣列 resolve的情況下出參也是陣列 且結果順序和呼叫順序一致
  3. 所有的值或者promise都完成才能resolve 所有要計數
  4. 只要有一個為reject 返回的Promise便reject

10. Proise.race 特點

  1. 返回一個Promise
  2. 入參是陣列 那麼出參根據第一個成功或者失敗的引數來確定
  3. 只要有一個resolve 或者reject 便更改返回Promise的狀態

 

const PENDING = 'pending' //等待
const FULFILLED = 'fulfilled' //成功
const REJECTED = 'rejected' //失敗

const fulfilledCallback = [] //成功回撥函式
const rejectedCallback = []  //失敗回撥函式

class MyPromise {
   
    constructor (executor) {
        
        try{
            executor(this.resolve, this.reject)
        } catch (e){
            this.reject(e)
        }
    }

    status = PENDING//promise的狀態
    value = undefined//成功之後的值
    reason = undefined//失敗之後的值
    fulfilledCallback = [] //成功回撥函式
    rejectedCallback = []  //失敗回撥函式
    resolve = value => {
        //如果狀態不是等待, 阻止程式繼續往下執行
        if(this.status !== PENDING){
            return
        }
        this.status = FULFILLED
        this.value = value
        //判斷成功回撥是否存在,如果存在, 呼叫
        // this.fulfilledCallback && this.fulfilledCallback(this.value)
        while(this.fulfilledCallback.length) this.fulfilledCallback.shift()()

    }
    reject = reason => {
        //如果狀態不是等待, 阻止程式繼續往下執行
        if(this.status !== PENDING){
            return
        }
        this.status = REJECTED
        this.reason = reason
        //判斷失敗回撥是否存在,如果存在, 呼叫
        // this.rejectedCallback && this.rejectedCallback(this.reason)
        while(this.rejectedCallback.length) this.rejectedCallback.shift()()
    }
    then = (fulfilledCallback, rejectedCallback) => {
        fulfilledCallback = fulfilledCallback ? fulfilledCallback : value => value
        rejectedCallback = rejectedCallback ? rejectedCallback : reason => {throw reason}
        let promise2 = new MyPromise((resolve, reject) => {
            
            //判斷狀態
            if(this.status === FULFILLED){
                setTimeout(() => {
                    try {
                        //判斷x 傳過來的可能是promise,先檢視promise返回的結果,在決定是用resolve還是reject,
                        //如果是普通值,直接呼叫resolve
                        let x = fulfilledCallback(this.value)
                        //外面載入完,才能獲取到promise2,用非同步解決
                        resolvePromise(promise2,x,resolve, reject)
                    } catch (error) {
                        reject(error)
                    }
                    
                },0)
               
            }else if(this.status === REJECTED){
                
                setTimeout(() => {
                    try {
                        //判斷x 傳過來的可能是promise,先檢視promise返回的結果,在決定是用resolve還是reject,
                        //如果是普通值,直接呼叫resolve
                        let x = rejectedCallback(this.reason)
                        //外面載入完,才能獲取到promise2,用非同步解決
                        resolvePromise(promise2,x,resolve, reject)
                    } catch (error) {
                        reject(error)
                    }
                    
                },0)
            }else{
                //等待狀態
                this.fulfilledCallback.push(() => {
                    setTimeout(() => {
                        try {
                            //判斷x 傳過來的可能是promise,先檢視promise返回的結果,在決定是用resolve還是reject,
                            //如果是普通值,直接呼叫resolve
                            let x = fulfilledCallback(this.value)
                            //外面載入完,才能獲取到promise2,用非同步解決
                            resolvePromise(promise2,x,resolve, reject)
                        } catch (error) {
                            reject(error)
                        }
                        
                    },0)
                });
                this.rejectedCallback.push(() => {
                    setTimeout(() => {
                        try {
                            //判斷x 傳過來的可能是promise,先檢視promise返回的結果,在決定是用resolve還是reject,
                            //如果是普通值,直接呼叫resolve
                            let x = rejectedCallback(this.reason)
                            //外面載入完,才能獲取到promise2,用非同步解決
                            resolvePromise(promise2,x,resolve, reject)
                        } catch (error) {
                            reject(error)
                        }
                        
                    },0)
                });
            }
        })
        return promise2
    }

    static all (array) {
        let result= []
        let index = 0;

        return new MyPromise((resolve, reject) => {

            function addData (key, value) {
                result[key] = value
                index++
                if (index === array.length) {
                    resolve(result)
                }
            }

            for (let i = 0; i < array.length; i++) {
                
                if (array[i] instanceof MyPromise) {
                    //promise物件
                    array[i].then(value => addData(i, value), reason => reject(reason))
                } else {
                    //普通值, 放到陣列裡
                    addData(i, array[i])
                }
            }
        })

    }

    static resolve (value) {
        if(value instanceof MyPromise) return value
        return new MyPromise(resolve => resolve(value))

    }

    finally (callback) {
        return this.then(value => {
            return MyPromise.resolve(callback()).then(() => value)
        }, reason => {
            return MyPromise.resolve(callback()).then(() => {throw reason})
        })

    }

    catch (rejectedCallback) {
        return this.then(undefined, rejectedCallback)
    }

}

function resolvePromise(promise2,x,resolve, reject){

    if(x === promise2){
        return reject(new TypeError('啦啦啦啦'))
    }
    if(x instanceof MyPromise){
        //是promise
        //往下直接傳
        x.then(resolve,reject)
    }else{
        //普通值
        resolve(x)
    }
}

module.exports = MyPromise;