第3章 自定义Promise

88 阅读7分钟

3.1 定义整体结构

// 自定义Promise函数模块: IIFE
(function (window) {
  // Promise构造函数  excutor: 执行器函数(同步执行)
  function Promise(excutor) {
    
  }
  
  // Promise原型对象的then()指定成功和失败的回调函数,返回一个新的promise对象
  Promise.prototype.then = function (onResolved, onRejected) {

  }
 
  // Promise原型对象的catch()指定失败的回调函数,返回一个新的promise对象
  
  Promise.prototype.catch = function (onRejected) {

  }
  // Promise函数对象的resolve方法  返回一个指定结果的成功的promise
 
  Promise.resolve = function (value) {
    
  }

  // Promise函数对象的reject方法 返回一个指定reason的失败的promise
  
  Promise.reject = function (reason) {
      
  }


  // Promise函数对象的all方法 返回一个promise, 只有当所有proimse都成功时才成功, 否则只要有一个失败的就失败
  Promise.all = function (promises) {
      
  }
 
 // Promise函数对象的race方法 返回一个promise, 其结果由第一个完成的promise决定
  Promise.race = function (promises) {
        
  }

  // 向外暴露Promise函数
  window.Promise = Promise
})(window)

3.2 Promise构造函数的实现

当我们使用new 创建一个promsie实例对象时,给Promise构造函数传入了一个excutor函数,并且excutor函数中包含onResolve 和 onReject 回调函数。

function Promise(excutor) {
    function resolve (value) {
    }

    function reject (reason) {
      
    }
    // 立即执行excutor函数
    excutor(resolve,reject)
}

3.2.1 定义promise的状态

Promise中有3种状态,pendingresolved,rejected,那么Promsie中会有一个status用于存储状态;

// 自定义Promise函数模块: IIFE
 const PENDING = 'pending'
 const RESOLVED = 'resovled'
 const REJECTED = 'rejected'
(function (window) {
  // Promise构造函数  excutor: 执行器函数(同步执行)
  function Promise(excutor) {
    
  }
 // 向外暴露Promise函数
  window.Promise = Promise
})(window) 
  

3.2.2 定义存储结果的属性和存储回调函数的属性

状态的改变只有一次,resolve函数中称之为value,rejecte函数中我们称之为reason,所以我们只需一个属性变量用于存储结果数据;回调函数在状态改变后指定,也有可能在状态改变前指定,所以我们需要一个数组变量用来存储回调函数。

function Promise(excutor) {
   // 将当前promise对象保存起来
    const self = this
    self.status = PENDING // 给promise对象指定status属性, 初始值为pending
    self.data = undefined // 给promise对象指定一个用于存储结果数据的属性
    self.callbacks = [] // 每个元素的结构: { onResolved() {}, onRejected() {}}
}

3.2.3 resolve函数实现

function resolve (value) {
  // 如果当前状态不是pending, 直接结束
  if (self.status!==PENDING) {
    return
  }

  // 将状态改为resolved
  self.status = 'resolved'
  // 保存value数据
  self.data = value
  // 如果有待执行callback函数, 立即异步执行回调函数onResolved
  if (self.callbacks.length>0) {
    setTimeout(() => { // 放入队列中执行所有成功的回调
      self.callbacks.forEach(calbacksObj => {
        calbacksObj.onResolved(value)
      }) 
    });
  }

}

3.2.4 reject 函数实现

function reject (reason) {
  // 如果当前状态不是pending, 直接结束
  if (self.status!==PENDING) {
    return
  }

  // 将状态改为rejected
  self.status = REJECTED
  // 保存value数据
  self.data = reason
  // 如果有待执行callback函数, 立即异步执行回调函数onRejected
  if (self.callbacks.length>0) {
    setTimeout(() => { // 放入队列中执行所有成功的回调
      self.callbacks.forEach(calbacksObj => {
        calbacksObj.onRejected(reason)
      }) 
    });
  }
}

3.2.5 执行器异常处理

当我们抛出一个异常时,promsie的状态也会变为 rejected,因此我们要对excutor函数进行try--catch处理

function Promise(excutor) {
    function resolve (value) {
    }

    function reject (reason) {
      
    }
    // 立即执行excutor函数
   try {
      excutor(resolve, reject)
    } catch (error) { // 如果执行器抛出异常, promise对象变为rejected状态
      reject(error)
    }
}

3.3 Promise.prototype.then实现

基础结构

Promise.prototype.then = function(onResolved, onRejected) {
    const self = this
    return new Promise((resolve, reject) => {
        // 如果当前是pending状态,把回调函数保存起来
        if(self.status === PENDING) {
            self.callbacks.push({
                onResolved,
                onRejected
            })
        } else if(self.status === RESOLVED) {

        } else { // rejected

        }
    })
}

3.3.1 如果执行的resolve回调

  1. 如果抛出异常, return的promise就会失败, reason就是error
  2. 如果回调函数返回不是promise, return的promise就会成功, value就是返回的值
  3. 如果回调函数返回是promise, return的promise结果就是这个promise的结果
Promise.prototype.then = function(onResolved, onRejected) {
    const self = this
    return new Promise((resolve, reject) => {
        // 如果当前是pending状态,把回调函数保存起来
        if(self.status === PENDING) {
            self.callbacks.push({
                onResolved,
                onRejected
            })
        } else if(self.status === RESOLVED) {
            setTimeout(() => {
                try{
                    const result = onResolved(self.data)
                    if(result intanceof Promise) {
                        // 如果回调函数返回是promise, return的promise结果就是这个promise的结果
                        result.then(
                            value => resolve(value), // 当result成功时,让return的promise也成功
                            reason => reject(reason) // 当result失败时,让return的promise也失败
                        )
                    }else {
                        // 如果回调函数返回不是promise, return的promise就会成功, value就是返回的值
                        resolve(self.data)
                    }
                } catch(error) {
                    // 如果抛出异常, return的promise就会失败, reason就是error 
                    reject(error)
                }
            })
            
        } else { // rejected

        }
    })
}

3.3.2 如果执行的reject回调

当then方法中执行reject回调,返回的promise对象跟在执行resolve回调时情况类似

Promise.prototype.then = function(onResolved, onRejected) {
    const self = this
    return new Promise((resolve, reject) => {
        // 如果当前是pending状态,把回调函数保存起来
        if(self.status === PENDING) {
            self.callbacks.push({
                onResolved,
                onRejected
            })
        } else if(self.status === RESOLVED) {
            
        } else { // rejected
            setTimeout(() => {
                try{
                    const result = onRejected(self.data)
                    if(result intanceof Promise) {
                        // 如果回调函数返回是promise, return的promise结果就是这个promise的结果
                        result.then(
                            value => resolve(value), // 当result成功时,让return的promise也成功
                            reason => reject(reason) // 当result失败时,让return的promise也失败
                        )
                    }else {
                        // 如果回调函数返回不是promise, return的promise就会成功, value就是返回的值
                        resolve(self.data)
                    }
                } catch(error) {
                    // 如果抛出异常, return的promise就会失败, reason就是error 
                    reject(error)
                }
            })
            
        }
    })
}

3.3.3 如果是pending状态时

当前promise的状态是pending时,先把回调函数存起来,以供后续状态改变时使用;当调用resolve回调时,情况与3.3.1中执行的resolve回调保持一致;当调用rejecte回调时,情况与3.3.2中执行的reject回调保持一致;

Promise.prototype.then = function(onResolved, onRejected) {
    const self = this
    return new Promise((resolve, reject) => {
        // 如果当前是pending状态,把回调函数保存起来
        if(self.status === PENDING) {
            self.callbacks.push({
                onResolved(){
                    try{
                        const result = onResolved(self.data)
                        if(result intanceof Promise) {
                            // 如果回调函数返回是promise, return的promise结果就是这个promise的结果
                            result.then(
                                value => resolve(value), // 当result成功时,让return的promise也成功
                                reason => reject(reason) // 当result失败时,让return的promise也失败
                            )
                        }else {
                            // 如果回调函数返回不是promise, return的promise就会成功, value就是返回的值
                            resolve(self.data)
                        }
                    } catch(error) {
                        // 如果抛出异常, return的promise就会失败, reason就是error 
                        reject(error)
                    }
                },
                onRejected(){
                     try{
                        const result = onRejected(self.data)
                        if(result intanceof Promise) {
                            // 如果回调函数返回是promise, return的promise结果就是这个promise的结果
                            result.then(
                                value => resolve(value), // 当result成功时,让return的promise也成功
                                reason => reject(reason) // 当result失败时,让return的promise也失败
                            )
                        }else {
                            // 如果回调函数返回不是promise, return的promise就会成功, value就是返回的值
                            resolve(self.data)
                        }
                    } catch(error) {
                        // 如果抛出异常, return的promise就会失败, reason就是error 
                        reject(error)
                    }
               }
        } else if(self.status === RESOLVED) {

        } else { // rejected

        }
    })
}

3.3.4 抽取改变状态的handle方法

上述中我们发现有好多重复代码,因此我们可以把执行状态函数的操作抽取出来

Promise.prototype.then = function(onResolved, onRejected) {
    const self = this
    return new Promise((resolve, reject) => {
        function handle(callback) {
            try {
                const result = callback(self.data)
                // 3. 如果回调函数返回是promise, return的promise结果就是这个promise的结果
                if (result instanceof Promise) {
                  result.then(
                    value => resolve(value), // 当result成功时, 让 return的promise也成功
                    reason => reject(reason) // 当result失败时, 让 return的promise也失败
                  )
                } else {
                  // 3. 如果回调函数返回不是promise, return的promise就会成功, value就是返回的值
                  resolve(result)
                }

              } catch (error) {
                // 1. 如果抛出异常, return的promise就会失败, reason就是error
                reject(error)
              }
        }
        // 如果当前是pending状态,把回调函数保存起来
        if(self.status === PENDING) {
            self.callbacks.push({
                onResolved() {
                    // 如果当前是resolved状态, 异步执行onResolved并改变return的promise状态
                    handle(onResolve)
                }
                onRejected() {
                    // 如果当前是rejected状态, 异步执行onRejected并改变return的promise状态
                    handle(onReject)
                }
            })
        } else if(self.status === RESOLVED) {
            setTimeout(() => {
              handle(onResolved)
            })
        } else { // rejected
           setTimeout(() => {
              handle(onRejected)
            })
        }
    })
}

3.3.5 then方法的回调默认值

then方法中回调函数会有不传的情况

Promise.prototype.then = function(onResolved, onRejected) {
    onResolved = typeof onResolved==='function' ? onResolved : value => value // 向后传递成功的value
    // 指定默认的失败的回调(实现错误/异常传透的关键点)
    onRejected = typeof onRejected==='function' ? onRejected : reason => {throw reason} // 向后后传递失败的reason

    const self = this
    return new Promise((resolve, reject) => {
    }
}

3.4 Promise.prototype.catch实现

Promise.prototype.catch = function (onRejected) {
    return this.then(undefined, onRejected)
}

3.4 Promise.resolve 实现

Promise.resolve = function (value) {
    // 返回一个成功/失败的promise
    return new Promise((resolve, reject) => {
      // value是promise
      if (value instanceof Promise) { // 使用value的结果作为promise的结果
        value.then(resolve, reject)
      } else { // value不是promise  => promise变为成功, 数据是value
        resolve(value)
      }
    })
}

3.5 Promise.reject 实现

Promise.reject = function (reason) {
    // 返回一个失败的promise
    return new Promise((resolve, reject) => {
      reject(reason)
    })
}

3.6 Promise.race 实现

Promise.race = function (promises) {
    // 返回一个promise
    return new Promise((resolve, reject) => {
      // 遍历promises获取每个promise的结果
      promises.forEach((p, index) => {
        Promise.resolve(p).then(
          value => {// 一旦有成功了, 将return变为成功
            resolve(value)
          },
          reason => { // 一旦有失败了, 将return变为失败
            reject(reason)
          }
        )
      })
    })
}

3.7 Promise.all 实现

Promise.all = function (promises) {
    // 用来保存所有成功value的数组
    const values = new Array(promises.length) 
    // 用来保存成功promise的数量
    let resolvedCount = 0
    // 返回一个新的promise
    return new Promise((resolve, reject) => {
      // 遍历promises获取每个promise的结果
      promises.forEach((p, index) => {
        Promise.resolve(p).then(
          value => {
            resolvedCount++ // 成功的数量加1
            // p成功, 将成功的vlaue保存vlaues
            // values.push(value)
            values[index] = value

            // 如果全部成功了, 将return的promise改变成功
            if (resolvedCount===promises.length) {
              resolve(values)
            }

          },
          reason => { // 只要一个失败了, return的promise就失败
            reject(reason)
          }
        )
      })
    })
}

Promise.prototype.finally

当finally 返回一个rejeced 状态的promise对象时,依然可以支持链式调用。当finally 返回一个 resolved 状态的 promise对象 或 非 promise对象时,不支持链式调用

Promise.prototype.finally = function (onFinally) {
    return this.then(
      value => Promise.resolve(onFinally()).then(() => value),
      reason => Promise.resolve(onFinally()).then(() => { throw reason })
    )
}