本身實現一個Promise庫

源碼地址git

  1. 先看基本使用github

    const promise = new Promise((resolve, reject) => {
      resolve(value)
      // or reject(reason)
    })

    建立Promise時傳入的回調函數是當即執行的,因此咱們的Promise應該是這樣(用ts實現)typescript

    function BDuckPromise(fn: (resolve: (value: any) => void, reject: (reason: any) => void) => any) {
    
      function resolve(value: any) {
    
      }
    
      function reject(reason: any) {
    
      }
    
      fn(resolve, reject);
    
    }
  2. 每一個Promise對象都有三種生命狀態:PENDING(未開始)、FULFILLED(已完成)、REJECTED(已失敗)。生命狀態只能是PENDING => FULFILLED 或者 PENDING => REJECTED 且一旦發生改變不可逆轉。此時咱們的代碼是這樣,具備了狀態。promise

    enum STATE {
      PENDING = 0,
      FULFILLED = 1,
      REJECTED = 2
    }
    
    function BDuckPromise(fn: (resolve:(value: any) => void, reject: (reason: any) => void) => any) {
      let store = null,
        state = STATE.PENDING
    
    
      function resolve(value: any): void {
        store = value;
        state = STATE.FULFILLED;
      }
    
      function reject(reason: any): void {
        store = reason;
        state = STATE.REJECTED;
      }
    
      fn(resolve, reject)
    }
  3. 一個Promise對象回調中傳入的值(value)或者拒因(reason)是在該示例對象的then函數中獲取的函數

    promise.then(value => {
      console.log(value);
      return value + 1
    }, reason => {
      // ....
    })

    then具備兩個回調函數onfulfilled(用於成功時傳遞value)、onrejected(用於失敗時傳遞reason)this

    因此咱們then方法大概是長這樣子code

    function BDuckPromise() {
      this.then = (onfulfilled, onrejected) => {
        if(state === STATE.PENDING) {
          return
        }
    
        if(state === STATE.FULFILLED) {
          onfulfilled(store)
          return
        }
    
        if(state === STATE.REJECTED) {
          onrejected(store)
          return
        }
      }
    }

    可是等一下,若是咱們寫成這個樣子當咱們調用then的時候就必需要求promise的狀態已經發生過改變咱們才能獲取到value或者reason,這個顯然不是咱們須要的。可是咱們應該要寫成什麼樣呢?分析一下對象

    當咱們調用then時候promise仍然處於pending狀態時,咱們應該怎麼將value或者reason在它狀態發生改變是傳遞出去呢?ip

    顯然,咱們應該在狀態發生改變時調用對應的onfulfilled或者onrejected回調。jsx

    那麼咱們就應該在狀態爲pending時將回調函數都存儲起來,一旦狀態改變了,就調用這些回調函數,這下就清楚了,應當在resolve或者reject中調用咱們的onfulfilled或者onrejected回調

    enum STATE {
      PENDING = 0,
      FULFILLED = 1,
      REJECTED = 2
    }
    
    function BDuckPromise(fn: (resolve:(value: any) => void, reject: (reason: any) => void) => any) {
      let store = null,
        state = STATE.PENDING,
        callbacks = [];
    
      function resolve(value: any): void {
        store = value;
        state = STATE.FULFILLED;
        callbacks.forEach(callback => {
          if(callback.onfulfilled && 'function' === typeof callback.onfulfilled) {
            callback.onfulfilled(store)
          }
        });
         callbacks = null
      };
    
      function reject(reason: any): void {
        store = reason;
        state = STATE.REJECTED;
        callbacks.forEach(callback => {
          if(callback.onrejected && 'function' === typeof callback.onrejected) {
            callback.onrejected(store)
          }
        });
         callbacks = null
      };
    
      this.then = (onfulfilled, onrejected) => {
        if(state === STATE.PENDING) {
          callbacks.push({
            onfulfilled,
            onrejected
          })
          return
        }
    
        if(state === STATE.FULFILLED) {
          onfulfilled(store)
          return
        }
    
        if(state === STATE.REJECTED) {
          onrejected(store)
          return
        }
      };
      fn(resolve, reject)
    }
  4. then函數是有返回值的,且返回的的是一個新的Promise對象,因此還得改=_=!

    const promise1 = new Promise((resolve, reject) => {
      resolve(1)
    })
    // promise2 是一個新的Promise對象
    const promise2 = promise1.then(value => {
      return value + 1
    })

    如今改爲這樣子

    this.then = (onfulfilled, onrejected) => {
        return new BDuckPromise((_resolve, _reject) => {
          if(state === STATE.PENDING) {
            callbacks.push({
              onfulfilled,
              onrejected
            })
            return
          }
    
          if(state === STATE.FULFILLED) {
            onfulfilled(store)
            return
          }
    
          if(state === STATE.REJECTED) {
            onrejected(store)
            return
          }
        });
      }
  5. 上一個then函數中return的值會傳遞給下一個then中做爲值

    const promise1 = new Promise((resolve, reject) => {
      resolve(1)
    })
    // promise2 是一個新的Promise對象
    const promise2 = promise1.then(value => {
      return value + 1
    })
    .then(value => {
      console.log(value) // 2
    })

    好吧,接着改=_=

    this.then = (onfulfilled, onrejected) => {
        return new BDuckPromise((_resolve, _reject) => {
          if(state === STATE.PENDING) {
            callbacks.push({
              onfulfilled,
              onrejected,
              _resolve,
              _reject
            })
            return
          }
    
          if(state === STATE.FULFILLED) {
            const ret = onfulfilled(store)
            _resolve(ret)
            return
          }
    
          if(state === STATE.REJECTED) {
            const ret = onrejected(store)
            _reject(ret)
            return
          }
        });
      }
    
    // 相應的resolve, reject也作相應的更改
    function resolve(value: any): void {
      store = value;
      state = STATE.FULFILLED;
      callbacks.forEach(callback => {
        if(callback.onfulfilled && 'function' === typeof callback.onfulfilled) {
          const ret = callback.onfulfilled(store)
          callback._resolve(ret)
        }
      })
    }
    
    function reject(reason: any): void {
      store = reason;
      state = STATE.REJECTED;
      callbacks.forEach(callback => {
        if(callback.onrejected && 'function' === typeof callback.onrejected) {
          const ret = callback.onrejected(store)
          callback._reject(ret)
        }
      })
    }
  6. 若是then中return的是一個新的Promise則下一個then中的value或reason是這個返回的Promise中resolve或者reject中傳遞value或者reason

    enum STATE {
      PENDING = 0,
      FULFILLED = 1,
      REJECTED = 2
    }
    
    function BDuckPromise(fn: (resolve:(value: any) => void, reject: (reason: any) => void) => any) {
      let store:any = null,
        state = STATE.PENDING,
        callbacks:any = []
    
    
      function resolve(value: any): void {
        setTimeout(() => {
          state = STATE.FULFILLED;
          // value 是一個Promise對象
          if(value && 'object' === typeof value && value.then && 'function' === typeof value.then) {
            // do then
            value.then(resolve, reject)
            return
          }
          // value 不是Promise對象
          store = value;
          callbacks.forEach(callback => {
            if(callback.onfulfilled && 'function' === typeof callback.onfulfilled) {
              const ret = callback.onfulfilled(store)
              callback._resolve(ret)
            }
          })
          callbacks = []
        })
      }
    
      function reject(reason: any): void {
        setTimeout(() => {
          state = STATE.REJECTED;
          // value 是一個Promise對象
          if(reason && 'object' === typeof reason && reason.then && 'function' === typeof reason.then) {
            reason.then(resolve, reject)
            return
          }
          // value 不是Promise對象
          store = reason;
          callbacks.forEach(callback => {
            if(callback.onrejected && 'function' === typeof callback.onrejected) {
              const ret = callback.onrejected(store)
              callback._reject(ret)
            }
          })
          callbacks = []
        }, 0)
      }
    
      this.then = (onfulfilled, onrejected) => {
        return new BDuckPromise((_resolve, _reject) => {
          if(state === STATE.PENDING) {
            callbacks.push({
              onfulfilled,
              onrejected,
              _resolve,
              _reject
            })
            return
          }
    
          if(state === STATE.FULFILLED) {
            const ret = onfulfilled(store)
            _resolve(ret)
            return
          }
    
          if(state === STATE.REJECTED) {
            const ret = onrejected(store)
            _reject(ret)
            return
          }
        });
      }
    
      fn(resolve, reject)
    }
    export default BDuckPromise;

還有reject的處理,目前是不合規範的

大概就是這樣,不搞了

相關文章
相關標籤/搜索