Promise(3) - 手写Promise/A+的实现

手写Promise

整体架构

(img-2ygDM59G-1591101279398)(Promise.assets/image-20200504083131613.png)]

Es5的写法

~(function (window) {
  const PENDING = 'pending'
  const RESOLVED = 'resolved'
  const REJECTED = 'rejected'

  function Promise(executor) {
    this.state = PENDING
    this.data = null
    this.callbacks = []

    function resolve(value) {
      // Promise的状态只能改一次,所以只有pending状态时候才能执行resolve和reject
      // 当Promise的状态为resolved|rejected就不能再次改变状态了
      if (this.state !== PENDING) {
        return
      }

      this.state = RESOLVED
      this.data = value

      if (this.callbacks.length > 0) {
        setTimeout(() => {
          this.callbacks.forEach(callbacksObj => {
            callbacksObj.onResolved(value)
          })
        })
      }
    }

    function reject(reason) {
      // Promise的状态只能改一次,所以只有pending状态时候才能执行resolve和reject
      // 当Promise的状态为resolved|rejected就不能再次改变状态了
      if (this.state !== PENDING) {
        return
      }

      this.state = REJECTED
      this.data = reason

      if (this.callbacks.length > 0) {
        setTimeout(() => {
          this.callbacks.forEach(callbacksObj => {
            callbacksObj.onRejected(reason)
          })
        })
      }
    }

    try {
      executor(resolve.bind(this), reject.bind(this))
    } catch (e) {
      // 执行器抛出异常,Promise状态为失败,调用reject
      reject(e)
    }
  }

  Promise.prototype = {
    constructor: Promise,

    then(onResolved, onRejected) {
      // 指定默认的回调函数
      // 如果用户没有指定onRejected | onResolved 我们需要把值|异常穿透下去
      // 异常穿透的关键一步,内部会捕捉并返回一个状态失败的Promise
      onRejected = typeof onRejected === 'function' ? onRejected : reason => {
        throw reason
      }
      onResolved = typeof onResolved === 'function' ? onResolved : value => value


      // 1. then中的回调函数发生异常,then返回失败的Promise,reason为异常
      // 2. then的回调函数运行,返回非Promise值,then返回成功的Promise,value为return的值
      // 3. then的回调函数运行,返回Promise,则then返回该promise
      const self = this

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

        function handle(callback) {
          try {
            const result = callback(self.data)
            if (result instanceof Promise) {
              // 第3种情况,得到返回的promise值|原因,并改变返回的promise状态
              result.then(resolve, reject)
            } else {
              // 第2种情况 
              resolve(result)
            }
          } catch (e) {
            // 第1种情况 
            reject(e)
          }
        }

        if (self.state === PENDING) {
          // Promise状态为pending,先把回调函数放到队列里
          self.callbacks.push({
            onResolved() {
              handle(onResolved)
            },
            onRejected() {
              handle(onRejected)
            }
          })
        } else if (self.state === RESOLVED) {
          // Promise状态为resolved,异步执行回调函数,并通过handle改变return的Promise
          setTimeout(() => {
            handle(onResolved)
          })
        } else {
          // Promise状态为rejected,异步执行回调函数,并通过handle改变return的Promise
          setTimeout(() => {
            handle(onRejected)
          })
        }
      })
    },

    catch (onRejected) {
      // 第一个参数写null,内部会把value数据向下传递
      return this.then(null, onRejected)
    }
  }

  Promise.resolve = function (value) {
    // value 可以是Promise,也可以是值
    // Promise => 根据promise状态改变return的状态
    // 值 => 成功的Promise
    return new Promise((resolve, reject) => {
      if (value instanceof Promise) {
        value.then(resolve, reject)
      } else {
        resolve(value)
      }
    })
  }
  Promise.reject = function (reason) {
    return new Promise((resolve, reject) => {
      reject(reason)
    })
  }
  Promise.all = function (iterable) {
    return new Promise((resolve, reject) => {
      const arr = new Array(iterable.length)
      const counter = 0
      iterable.forEach((p, index) => {
        // 如果iterable中有值不是promise,那么包装成promise
        Promise.resolve(p).then(
          value => {  // 执行onResolved几次,就成功几次
            // 这里不能用value代替counter,因为所有的操作都是异步的,不能确定谁先完成,如果最后一个先完成就会出问题
            arr[index] = value
            counter++
            counter === arr.length  ? resolve(arr) : null
          },
          reason => { // 只要有一个失败,整个promise失败
            reject(reason)
          }
        )
      })  
    })
  }
  
    Promise.all(iterable) {
    return new Promise((resolve, reject) => {
      let arr = []
      iterable.forEach((p, index) => {
        Promise.resolve(p).then(
          value => {
            arr[index] = value
            if(arr.length === iterable.length) {
              resolve(arr)
            }
          } ,
          reason => {
            reject(reason)
          }
        )
      })
    })
  }
  
  Promise.race = function (iterable) {
    return new Promise((resolve, reject) => {
      iterable.forEach(p => {
        // 如果iterable中有值不是promise,那么包装成promise
        Promise.resolve(p).then(
          value => {
            // 先成功,先调用,后续的不再改变状态
            resolve(value)
          },
          reason => {
            // 先失败,先调用,后续的不再改变状态
            reject(reason)
          }
        )
      })
    })
  }

  // 自定义工具方法
  Promise.resolveDelay = function(value, time) {
    /**
     *  返回一个成功的Promise对象,它在指定时间后才能成功
     */
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        if (value instanceof Promise) {
          value.then(resolve, reject)
        } else {
          resolve(value)
        }
      }, time)
    })
  }

  Promise.rejectDelay = function(reason, time) {
    /**
     *  返回一个Promise对象,它在指定时间后才能确定失败
     */
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        reject(reason)
      }, time)
    })
  }


  window.Promise = Promise
})(window)

Class写法

const PENDING = 'pending'
const RESOLVED = 'resolved'
const REJECTED = 'rejected'

class Promise {

  constructor(executor) {
    this.state = PENDING
    this.data = null;
    this.callbacks = []

    let resolve = value => {
      if(this.state !== PENDING) {
        return
      }
      this.state = RESOLVED
      this.data = value
      if(this.callbacks.length) {
        process.nextTick(() => {
          this.callbacks.forEach(item => {
            item.onResolved(this.data)
          })
        })
      }
    }

    let reject = reason => {
      if(this.state !== PENDING) {
        return
      }
      this.state = REJECTED
      this.data = reason
      if(this.callbacks.length) {
        process.nextTick(() => {
          this.callbacks.forEach(item => {
            item.onRejected(this.data)
          })
        })
      }
    }

    try {
      executor(resolve, reject)
    } catch(e) {
      reject(e)
    }
  }

  then(onResolved, onRejected) {
    onResolved = typeof onResolved === 'function' ? onResolved : value => value
    onRejected = typeof onRejected === 'function' ? onRejected : reason => {throw reason}

    return new Promise((resolve, reject) => {
      let handle = callback => {
        try {
          const result = callback(this.data)
          if(result instanceof Promise) {
            result.then(resolve, reject)
          } else {
            resolve(result)
          }
        } catch(e) {
          reject(e)
        }
      }

      if(this.state === PENDING) {
        this.callbacks.push({
          onResolved() {
            handle(onResolved)
          }, 
          onRejected() {
            handle(onRejected)
          }
        })
      } else if(this.state === RESOLVED) {
        process.nextTick(() => {
          handle(onResolved)
        })
      } else {
        process.nextTick(() => {
          handle(onRejected)
        })
      }
    })
  }

  catch(onRejected) {
    return this.then(null, onRejected)
  }

  static resolve(value) {
    return new Promise((resolve, reject) => {
      if(value instanceof Promise) {
        value.then(resolve, reject)
      } else {
        resolve(value)
      }
    })
  }

  static reject(reason) {
    return new Promise((resolve, reject) => {
      if(reason instanceof Promise) {
        reason.then(reject, reject)
      } else {
        reject(reason)
      }
    })
  }

  static all(iterable) {
    return new Promise((resolve, reject) => {
      const  arr = []
      let counter = 0
      iterable.forEach((p, index) => {
        Promise.resolve(p).then(
          value => {
            counter++
            arr[index] = value
            if(counter === iterable.length) {
              resolve(arr)
            }
          },
          reason => {
            reject(reason)
          }
        )
      })
    })
  }
}

module.exports = Promise

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值