565 手写promise源码

// 考虑到兼容性问题,不使用ES6+
; (function () {
  // 构造函数constructor
  function MyPromise(executor) {
    // 参数合法校验
    if (typeof executor !== "function") {
      throw new TypeError('MyPromise resolver ' + executor + ' is not a function');
    }

    // 设置实例的私有属性
    var _this = this;
    this.PromiseStatus = 'pending';
    this.PromiseValue = undefined;
    // 【1、实例的resolveFunc函数、rejectFunc函数,为了拿到then中的2个函数,把这2个函数挂载到实例上; 2、值设置为空函数的好处,就是支持resolve方法中不写then。】
    this.resolveFunc = function () { };
    this.rejectFunc = function () { };

    // 修改实例的状态和value:只有当前状态为pending才能修改状态
    function change(status, value) {
      // 下面的_this.PromiseStatus不能用传递进来的status
      if (_this.PromiseStatus !== "pending") return;
      _this.PromiseStatus = status;
      _this.PromiseValue = value;
      // 通知基于.then注入的某个方法执行(执行resolve、reject都是异步的) 
      // 【用等待时间为0的setTimeout模拟微任务】
      var delayTimer = setTimeout(function () {
        clearTimeout(delayTimer);
        delayTimer = null;
        // 不用重新定义变量,直接用上面的_this.PromiseStatus、_this.PromiseValue即可
        var status = _this.PromiseStatus;
        var value = _this.PromiseValue;
        // 把.then注入的某个方法执行拿出来执行
        status === "fulfilled" ?
          _this.resolveFunc.call(_this, value) :
          _this.rejectFunc.call(_this, value);
      }, 0);
    }

    // new MyPromise的时候会给 resolve函数传参value
    function resolve(value) {
      change('fulfilled', value);
    }

    // new MyPromise的时候会给 reject函数传参reason
    function reject(reason) {
      change('rejected', reason);
    }

    // new MyPromise的时候会立即把executor函数执行,executor函数中的第一、二个参数分别为resolve、reject函数
    // executor函数执行出现错误,也会把实例的状态改为失败,且value是失败的原因
    try {
      // 【执行executor,就会根据情况执行resolve、reject中的一个,然后去执行change,再然后决定执行resolveFunc、rejectFunc中的一个】
      executor(resolve, reject);
    } catch (err) {
      change('rejected', err.message);
    }
  }

  // 把MyPromise当作对象
  MyPromise.resolve = function (value) {
    // 创建一个状态为成功的实例,通知这个实例的then中的某个方法执行。如果没有写then,定时器到达一定时间之后,就会去执行成功或失败的方法,但是实例没有成功和失败的方法。
    return new MyPromise(function (resolve) {
      resolve(value);
    });
  };

  MyPromise.reject = function (reason) {
    // function的形参可以下划线占位,不能用null
    return new MyPromise(function (_, reject) {
      reject(reason);
    });
  };

  // MyPromise.prototype
  // 不仅要把resolveFunc、rejectFunc挂载到 实例上,还要知道resolveFunc、rejectFunc执行的时候,是否报错,以及返回值是什么;最后还要返回一个新的promise实例
  MyPromise.prototype.then = function (resolveFunc, rejectFunc) {
    // 参数不传默认值的处理:目的是实现状态的顺延 【不传,或者传的不是函数】
    if (typeof resolveFunc !== "function") {
      // (1) 形参value从哪来?promise实例中执行resolve()传递的数据;加一个函数,这个函数可以接收到value; (2) 不是this.resolveFunc
      resolveFunc = function (value) {
        // 【不传,或者传的不是函数时】怎么往下顺延呢?返回一个resolve即可
        return MyPromise.resolve(value);
      };
    }

    if (typeof rejectFunc !== "function") {
      rejectFunc = function (reason) {
        return MyPromise.reject(reason);
      };
    }

    var _this = this;
    // resolveFunc、rejectFunc执行的成功、失败直接影响了新返回的MyPromise的成功、失败
    // 返回的新实例的成功和失败由resolveFunc、rejectFunc执行是否报错来决定,或者由返回值是否为新的MyPromise实例来决定
    return new MyPromise(function (resolve, reject) {
      // 最终目的是执行resolveFunc,外面包一层匿名函数,是想知道resolveFunc执行时,是否报错,返回值是什么
      // document.body.onclick = fn,如果想 改变fn的值、this、预先传参等等,就先绑定一个匿名函数,document.body.onclick = function() { fn() }
      // value 要写在外层的匿名函数中
      _this.resolveFunc = function (value) {
        // 这里面的this就是实例了,因为执行change方法,传过来的就是实例,也可以用this写
        try {
          // 1、用不用call改变this都可以;2、then的2个回调函数参数有返回值; 3、value是resolveFunc接收【实例】的返回结果
          var x = resolveFunc.call(_this, value);
          // 1、不是promise实例,一定是成功的,执行resolve;2、如果x是promise实例,then会通知resolve或reject执行,通知resolve执行,返回的new MyPromise就是成功的,通知reject执行,返回的new MyPromise就是失败的。如果返回的新实例x是失败的,就执行reject,new MyPromise就是失败的,反之是成功的。
          x instanceof MyPromise ? x.then(resolve, reject) : resolve(x);
        } catch (err) {
          reject(err.message);
        }
      };

      _this.rejectFunc = function (reason) {
        try {
          var x = rejectFunc.call(_this, reason);
          x instanceof MyPromise ? x.then(resolve, reject) : resolve(x);
        } catch (err) {
          reject(err.message);
        }
      };
    });
  };

  MyPromise.prototype.catch = function (rejectFunc) {
    return this.then(null, rejectFunc);
  };

  MyPromise.all = function (promiseArr) {
    return new MyPromise(function (resolve, reject) {
      var index = 0; // 成功的个数
      var values = [];

      for (var i = 0; i < promiseArr.length; i++) {
        // 利用闭包的方式保存循环的每一项索引
        (function (i) {
          var item = promiseArr[i];
          // 如果当前项不是Promise,直接算作当前项成功
          !(item instanceof MyPromise) ? item = MyPromise.resolve(item) : null;
          // 回调函数的参数 value、reason来自于 race中的参数 promise实例的promiseValue
          item.then(function (value) {
            index++;
            // 不是values[i] = item,item是promise实例,value才是实例的值
            values[i] = value;
            if (index >= promiseArr.length) {
              resolve(values); // 所有的实例都是成功的
            }
          }).catch(function (reason) {
            reject(reason); // 只要有一个失败,整体就是失败的
          });
        })(i);
      }
    });
  };

  // 补充race
  MyPromise.race = function (promises) {
    return new MyPromise(function (resolve, reject) {
      promises.forEach(function (p) {
        !(p instanceof MyPromise) ? p = MyPromise.resolve(p) : null
        // 回调函数的参数 value、reason来自于 race中的参数 promise实例的promiseValue
        p.then(function (value) {
          resolve(value)
        }).catch(function (reason) {
          reject(reason)
        })
      })
    })
  }

  // 补充finally
  Promise.prototype.finally = function (callback) {
    let P = this.constructor;
    // 不管成功、失败,都会执行callback,放到this.then中,成功执行P.resolve,并在P.resolve中执行callback;失败同理。
    return this.then(
      value => P.resolve(callback()).then(() => value),
      reason => P.resolve(callback()).then(() => { throw reason })
    );
  };

  window.MyPromise = MyPromise;
})();


// ------------------------------------

function fn1() {
  return MyPromise.resolve(1);
}

function fn2() {
  return new MyPromise((resolve, reject) => {
    setTimeout(() => {
      resolve(2);
    }, 2000);
  });
}

function fn3() {
  return new MyPromise((resolve, reject) => {
    setTimeout(() => {
      reject(3);
    }, 1000);
  });
}

MyPromise.all([fn1(), fn2(), fn3(), 10])
  .then(function (values) {
    console.log('OK', values);
  })
  .catch(function (reason) {
    console.log('NO', reason);
  });


new MyPromise(function (resolve, reject) {
  // resolve(10);
  reject(20);
}).then(function (value) {
  console.log('OK', value);
  return MyPromise.reject(200);
},
  /* function (reason) {
  console.log('NO', reason);
  return 100;
} */
).then(function (value) {
  console.log('OK', value);
}, function (reason) {
  console.log('NO', reason);
});
原文地址:https://www.cnblogs.com/jianjie/p/13877799.html