手写一个简易的Promise

272 阅读4分钟

本文手写了一个简易Promise,分别使用了es5、es6两种方式进行模拟。看完本文预计需要3-5分钟。看懂本文你需要明确以下知识点:

  1. 构造函数及原型链
  2. class类继承
  3. this指向
    this指向:看调用方式

    1. 直接调用函数  windowES5 严格模式 this 指向 undefined
    2. 隐式调用(对象调用方式) 调用的对象
      a.b.c.d() 指向c
    3. 显示调用(call/apply) 指向传入的第一个参数
    4. new调用 指向产生的实例对象
    
    5. 回调函数
      定时器回调函数 windowES5 严格模式 this 指向 undefined
      DOM事件回调函数 绑定事件的DOM元素
      React生命周期函数 组件实例对象
      React普通函数 默认是undefined
    
    6. 箭头函数
      没有自己的thisarguments
      看离他最近包裹它函数的this

方式一(es5):

  • es没有模块暴露的方法,通常使用立即函数自调用的方式挂载到window上(即IIFE)。
(function (w) {
  function MyPromise(executor) {
    // promise对象就是this --> new关键字
    const that = this;
    // 以'_'开头的属性作为私有属性,外界不允许操作
    // 初始化promise对象状态是pending状态
    that._status = "pending";
    //初始化返回的结果容器(resolve或reject中返回的值会存到_result中)
    that._result = undefined;
    // 用来存储成功、失败回调函数的容器(其实存放的就是then或catch方法中的回调函数)
    that._callbacks = {};

    function resolve(value) {
      // 先进行判断,promise对象状态只能修改一次
      if (that._status !== "pending") return;
      // 将promise对象状态改成成功状态resolved
      that._status = "resolved";
      // 把resolve的结果值存放到_result中
      this._result = value;
      // 触发/调用 onResolved 函数
      setTimeout(function () {
        // 异步调用 setTimeout
        // 新的运算符 ?. 可选链表示存在就调用等同于 that._callbacks.onResolved && that._callbacks.onResolved(value);
        that._callbacks.onResolved?.(value);
        //需要注意,此处的this.callbacks.onResolved其实就是then或catch方法中的回调(把then方法联系在一起思考)
      }, 0);
    }

    // 将promise对象状态改成失败状态rejected
    function reject(reason) {
      // 让promise对象状态只能修改一次
      if (that._status !== "pending") return;
      that._status = "rejected";
      // 存错错误原因
      this._result = reason;
      // 触发/调用 onRejected 函数
      setTimeout(function () {
      // 同上(resolve)
        that._callbacks.onRejected?.(reason);
      }, 0);
    }

    // 同步调用
    // executor为new Pormise(()=>{})时传入的回调函数
    executor(resolve, reject);
  }
  
  

  MyPromise.prototype.then = function (onResolved, onRejected) {
    // this指向实例对象promise
    // 将成功、失败回调添加容器中(注意:没有调用)
    const that = this;

    return new MyPromise(function (resolve, reject) {
      // onResolved为then方法中接收结果的回调,存入callbacks中,在上述resolve或reject中调用(关键点)
      that._callbacks.onResolved = function (value) {
        try {
          const result = onResolved(value);
          if (result instanceof MyPromise) {
            // 说明result是promise对象
            result.then(resolve, reject);
            // 等同于
            // result.then(
            //   (value) => resolve(value),
            //   (reason) => reject(reason)
            // );
          } else {
            // 说明没有返回值或者返回值不是promise
            resolve(result);
          }
        } catch (e) {
          reject(e);
        }
      };

      this._callbacks.onRejected = function (reason) {
        try {
          const result = onRejected(reason);
          if (result instanceof MyPromise) {
            // 说明result是promise对象
            result.then(resolve, reject);
            // 等同于
            // result.then(
            //   (value) => resolve(value),
            //   (reason) => reject(reason)
            // );
          } else {
            // 说明没有返回值或者返回值不是promise
            resolve(result);
          }
        } catch (e) {
          reject(e);
        }
      };
    });
  };

  w.MyPromise = MyPromise;
})(window);

方式二(es6):

  • 基本过程与es5类似(参考es5写法),使用es6可以使写法更加简单
class MyPromise { 
    constructor(executor){ 
        this._status = "pending";
        this._result = undefined;
        // 用来存储成功、失败回调函数的容器
        this._callbacks = {};
        // executor 是一个执行器,进入会立即执行。 并传入resolve和reject方法 
        executor(this.resolve, this.reject) } 
    } 
    
    resolve(value) {
      // 让promise对象状态只能修改一次
      if (this._status !== "pending") return;
      // 将promise对象状态改成成功状态resolved
      this._status = "resolved";
      this._result = value;
      // 触发/调用 onResolved 函数
      setTimeout(function () {
        // 异步调用 setTimeout
        // this._callbacks.onResolved && this._callbacks.onResolved(value);
        // 新的运算符 ?. 可选链
        this._callbacks.onResolved?.(value);
      }, 0);
    }
    
    reject(reason) {
      // 让promise对象状态只能修改一次
      if (this._status !== "pending") return;
      this._status = "rejected";
      this._result = reason;
      // 触发/调用 onRejected 函数
      setTimeout(function () {
        this._callbacks.onRejected?.(reason);
      }, 0);
    }
    
    
    then(onResolved, onRejected) {
    // 将成功、失败回调添加容器中(注意:没有调用)
    return new MyPromise(function (resolve, reject) {
      this._callbacks.onResolved = function (value) {
        try {
          const result = onResolved(value);
          if (result instanceof MyPromise) {
            // 说明result是promise对象
            result.then(resolve, reject);
            // result.then(
            //   (value) => resolve(value),
            //   (reason) => reject(reason)
            // );
          } else {
            // 说明没有返回值或者返回值不是promise
            resolve(result);
          }
        } catch (e) {
          reject(e);
        }
      };

      this._callbacks.onRejected = function (reason) {
        try {
          const result = onRejected(reason);
          if (result instanceof MyPromise) {
            // 说明result是promise对象
            result.then(resolve, reject);
            // result.then(
            //   (value) => resolve(value),
            //   (reason) => reject(reason)
            // );
          } else {
            // 说明没有返回值或者返回值不是promise
            resolve(result);
          }
        } catch (e) {
          reject(e);
        }
      };
    });
  };
    
} 
// exports default = MyPromise
module.exports = MyPromise

本文模拟了一个简易版promise,跟着思路很容易就能理解,文章如果有什么问题欢迎在评论区指出共勉(撰文不易,点赞鼓励,感谢!)