手写promise

66 阅读3分钟

promise相关

  • 什么是promise规范?
    • 就像esjs的规范,jses的实现,js中的原生promise 是对promise/A+规范的实现
    • promise不止一个规范,有很多社区规范,比较全面的是promise/A+
  • jspromisethen是微任务,是因为浏览器引擎是用微任务实现的,规范中之规定了是异步任务即可

手写promise

原生promise形态:

let promise = new Promise((reslove, reject) => {})

需要实现和注意的点

  • 基本形态
    • 构造器来创建,参数传入函数,函数的参数是两个函数,外部可以用型参来调用类内部的函数,要注意this的绑定问题
    • 实例属性
      • 状态
      • 结果值
      • 回调函数数组(状态不会立即改变,用数组收集then中的回调函数)
  • 状态管理函数 resolve() reject()
    • 是个异步任务 这里使用setTimeout()宏任务模拟异步,但注意js中promise是个微任务
    • 修改实例的状态,和结果值
    • 遍历执行回调函数数组中的函数
  • 监听状态改变的函数 then, catch
    • then(f1, f2)参数必须是函数
    • then是链式调用的
    • resovePromise的实现(具体后面说明)
  • all() race()的实现

代码

class myPromise {
  //状态写成静态函数? 见插播知识点
  static PENDING = 'pending';
  static FULFILLED = 'fulfiled';
  static REJECTED = 'rejected';
  // 方便看到整体的结构,列出需要实现的函数
  constructor(func) {
   ...//拆解到下面代码中
  }

  resolve(result) {
    ...//拆解到下面代码中
  }

  reject(reason) {
   ...//拆解到下面代码中
  }
  
  then(onResolved, onRejected) {
   ...//拆解到下面代码中
  }

  race(paramsArr) {
    ...//拆解到下面代码中
  }
}
function resolvePromise() {
    ...//拆解到下面代码中
}

插播知识点:
静态函数和静态属性;
(1)基本形态和使用方法: 代码示例中展示了
(2)好处:无需创建实例;共享数据;避免全局命名冲突

  constructor(func) {
    this.promiseStatus = myPromise.PENDING;
    this.promiseResult = null;
    this.onFulfilledCallbacks = [];
    this.onRejectedCallbacks = [];
    try {
      /**
       * reslove是在实例外部调用,会使this丢失,
       * 用bind绑定this为实例中的this
       */
      func(this.resolve.bind(this), this.reject.bind(this));
    } catch (error) {
      this.reject(error);
    }
  }
  resolve(result) {
    setTimeout(() => {
      if (this.promiseStatus === myPromise.PENDING) {
        this.promiseStatus = myPromise.FULFILLED;
        this.promiseResult = result;
        /**
         * 执行then中收集的回调函数
         */
        this.onFulfilledCallbacks.forEach(callback => callback(result));
      }
    });
  }
  reject(reason) {
    setTimeout(() => {
      if (this.promiseStatus === myPromise.PENDING) {
        this.promiseStatus = myPromise.REJECTED;
        this.promiseResult = reason;
        this.onRejectedCallbacks.forEach(callback => callback(reason));
      }
    });
  }
  /**
   * 返回promise 可以链式调用
   * 根据状态来执行
   * 回调函数执行返回的值需要resolvePromise来处理
   * @param {*} onResolved 
   * @param {*} onRejected 
   * @returns 
   */
  then(onResolved, onRejected) {
    let promise = new myPromise((resolve, reject) => {
      if (this.promiseStatus === myPromise.PENDING) {
        this.onFulfilledCallbacks.push(() => {
          setTimeout(() => {
            try {
              if (typeof onResolved !== 'function') {
                resolve(this.promiseResult);
              } else {
                let value = onResolved(this.promiseResult);
                resolvePromise(promise, value, resolve, reject);
              }
            } catch (error) {
              reject(error);
            }
          });
        });

        this.onRejectedCallbacks.push(() => {
          setTimeout(() => {
            try {
              if (typeof onRejected !== 'function') {
                reject(this.promiseResult);
              } else {
                let value = onRejected(this.promiseResult);
                resolvePromise(promise, value, resolve, reject);
              }
            } catch (error) {
              reject(error);
            }
          });
        });
      }

      if (this.promiseStatus === myPromise.FULFILLED) {
        setTimeout(() => {
          try {
            if (typeof onResolved !== 'function') {
              resolve(this.promiseResult);
            } else {
              let value = onResolved(this.promiseResult);
              resolvePromise(promise, value, resolve, reject);
            }
          } catch (error) {
            reject(error);
          }
        });
      }

      if (this.promiseStatus === myPromise.REJECTED) {
        setTimeout(() => {
          try {
            if (typeof onRejected !== 'function') {
              reject(this.promiseResult);
            } else {
              let value = onRejected(this.promiseResult);
              resolvePromise(promise, value, resolve, reject);
            }
          } catch (error) {
            reject(error);
          }
        });
      }
    });

    return promise;
  }
//处理promise链式
  /**
   * then结果返回值处理函数,处理回调函数是promise的情况
   * 递归查找then的链
     /**
   * x值的处理
   * (1)x是基本类型
   * (2)是我们手写定义的promise对象
   * (3)是promise实例
   */
   * @param {*} promise then的返回值promise
   * @param {*} x then回调函数的返回值
   * @param {*} resolve 对x的处理函数 then的返回值promise中的
   * @param {*} reject 对x的处理函数 then的返回值promise中的
   * @returns 
   */
function resolvePromise(promise, x, resolve, reject) {
    if (x === promise) {
      throw new TypeError('chaining cycle detected for promise');
    }
    if (x instanceof myPromise) {
      x.then(y => {
        resolvePromise(promise, y, resolve, reject);
      }, reject);
    } else if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
      try {
        // 有then属性的对象 或者其他规范的promise,获取then属性,
        // get操作可能会有异常 需要try...catch
        var then = x.then;
      } catch (error) {
        return reject(error);
      }
      // then应该是个可执行函数
      if (typeof then === 'function') {
        // 添加一个锁,只执行一次
        let called = false;
        try {
          then.call( //执行 绑定x上下文
            x,
            y => {
              if (called) return;
              called = true;
              resolvePromise(promise, y, resolve, reject); //递归处理
            },
            rej => {
              if (called) return;
              called = true;
              reject(rej);
            }
          );
        } catch (error) {
          if (called) return;
          called = true;
          reject(error);
        }
      } else {
        resolve(x); //then不可执行,x只是一个有then属性的类promise对象
      }
    } else {
      resolve(x); //基本类型值处理
    }
  }

over!
flag:后续完善promise相关的知识:promise的设计理念; promise的执行顺序;基于promise封装的异步处理函数axios,fetch; promise的语法糖async/await