JavaScript异步编程--手写Promise

156 阅读4分钟

实现MyPromise

分析Promise原理

  • 首先Promise是使用new来进行初始化,所以Promise是一个类
  • 在初始化的时候我们需要传入一个函数进去,并且这个函数是理解执行的
  • 初始化传入的函数有两个参数,这两个参数都是函数类型,分别为:resolve、reject,这两个函数是用来改变Promise状态的
  • Promise有三种状态,分别为pending、fulfilled、rejected
  • Promise的状态可以发生变化,但是变化是由规则的即pending状态可以变化为fulfilled或rejected状态,一旦变化后不能改变
  • Promise有一个then方法,这个方法有两个参数,但是是可选的,第一个参数用于处理成功的回调,这个回调会传入成功的值;第二个参数是失败的回调,这个回调会传入失败的原因
  • then方法内部做状态判断,如果状态是成功就调用传入的成功回调,如果状态是失败就调用失败的回调
  • 同一个Promise对象下面的then方法是可以被调用多次的
  • then方法是可以被链式调用的,后面的then方法的回调函数拿到的值是上一个then方法的回调函数的返回值
  • Promise具有静态方法all、resolve、finally
  • Proimse具有异常捕捉方法catch

示例:

    // 常量状态
    const PENDING = 'PENDING'
    const FULFILLED = 'FULFILLED'
    const REJECTED = 'REJECTED'
    
    class MyPromise {
      // 构造函数
      constructor(exexutor) {
        // 传入的函数又叫执行器,这个执行器会被立即执行
        // 当运行执行器时内部出现错误,直接捕获并通过reject方法返回给外部
        try {
          exexutor(this.resolve, this.reject)
        } catch(e) {
          // 出现异常直接调用reject
          this.reject(e)
        }
      }
    
      // 由于状态我们需要在其他地方使用,所以讲状态保存为实例
      status = PENDING // 初始值为PENDING
      // 当then方法传入的回调是异步时,我们需要先将resolve和reject的值存储起来
      value = undefined
      error = undefined
      // 当then方法传入的回调是异步调用或者then被多次调用时需要将传入的回调存储起来
      successCallback = []
      failCallback = []
    
      // 处理成功回调的方法
      resolve = value => {
        // 因为执行器中不能同时执行resolve和reject,所以我们需要在做状态更改之前先判断状态
        if (this.status !== PENDING) return
        // 将状态更改为FULFILLED
        this.status = FULFILLED
        // 保存成功之后的值
        this.value = value
        // 判断成功回调是否存在,如果存在则调用并且兼容多次then调用
        while(this.successCallback.length) this.successCallback.shift()()
      }
    
      // 处理失败回调的方法
      reject = error => {
        // 处理方法同resolve类似
        if (this.status != PENDING) return
        this.status = REJECTED
        this.value = value
        while(this.failCallback.length) this.failCallback.shift()()
      }
    
      // then方法
      then(successCallback, failCallback) {
        // 因为then的参数是可选的,所以判断下当没有传入参数时处理下
        successCallback = successCallback ? successCallback : value => value
        failCallback = failCallback ? failCallback : error => { throw error }
        // then方法支持链式调用,所以我们需要返回一个新的Promise对象
        let promise2 = new Promise((resolve, reject) => {
          // 新返回的也需要先判断状态
          if (this.status === FULFILLED) {
            // 变为异步,否则拿不到promise2
            setTimeout(() => {
              try {
                let x = successCallback(this.value)
                // 此处需要判断下x是普通值还是Promise对象
                // 如果是普通值,直接调用resolve
                // 如果是peomise对象,需要查看Promise对象的返回结果决定调用resolve还是reject
                // 由于这个方法需要多次调用,封装起来
                resolvePromise(promsie2, x, resolve, reject)
              } catch (e) {
                reject(e)
              }
            }, 0);
          } else if (this.status == REJECTED) {
            // 处理同resolve
            setTimeout(() => {
              try {
                let x = failCallback(this.error);
                resolvePromise(promsie2, x, resolve, reject)
              }catch (e) {
                reject(e);
              }
            }, 0)
          } else {
            // 处理异步情况当前状态是PENDING
            // 将回调存储起来
            this.successCallback.push(() => {
              setTimeout(() => {
                try {
                  let x = successCallback(this.value)
                  resolvePromise(promsie2, x, resolve, reject)
                }catch (e) {
                  reject(e)
                }
              }, 0)
            });
            this.failCallback.push(() => {
              setTimeout(() => {
                try {
                  let x = failCallback(this.error)
                  resolvePromise(promsie2, x, resolve, reject)
                }catch (e) {
                  reject(e)
                }
              }, 0)
            })
          }
        })
        // 返回promise2
        return promise2
      }
    
      // 实现finally
      // 执行完成后无论成功还是失败都会执行
      finally (callback) {
        return this.then(value => {
          return MyPromise.resolve(callback()).then(() => value);
        }, error => {
          return MyPromise.resolve(callback()).then(() => { throw error })
        })
      }
    
      //catch,没有resolve方法的then
      catch (failCallback) {
        return this.then(undefined, failCallback)
      }
    
      // 静态resolve
      static resolve (value) {
        // 如果value是当前实例直接返回
        if (value instanceof MyPromise) return value;
        // 如果不是,那就包装下
        return new MyPromise(resolve => resolve(value));
      }
    
      // 静态all方法
      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++) {
            let current = array[i];
            if (current instanceof MyPromise) {
              // promise 对象
              current.then(value => addData(i, value), error => reject(error))
            }else {
              // 普通值
              addData(i, array[i]);
            }
          }
        })
      }
    
    }
    
    function resolvePromise(promsie2, x, resolve, reject) {
      // 此处判断避免循环调用自己
      if (promsie2 === x) {
        return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
      }
      if (x instanceof MyPromise) {
        x.then(resolve, reject)
      } else {
        resolve(x)
      }
    }