自己实现一个Promise库

源码地址

  1. 先看基本使用

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

    创建Promise时传入的回调函数是立即执行的,所以我们的Promise应该是这样(用ts实现)

    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 且一旦发生改变不可逆转。此时我们的代码是这样,具有了状态。

    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)

    所以我们then方法大概是长这样子

    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在它状态发生改变是传递出去呢?

    显然,我们应该在状态发生改变时调用对应的onfulfilled或者onrejected回调。

    那么我们就应该在状态为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的处理,目前是不合规范的

大概就是这样,不搞了

posted @ 2018-09-04 17:35  郑闯  阅读(161)  评论(0编辑  收藏  举报