勇敢猿猿,不怕困难!!!---手写Promise(下)

226 阅读3分钟

这部分是手写Promsie的重头戏,没看我手写Promise(上)的同学,请先看完

勇敢猿猿,不怕困难!!!---手写Promise(上)

重头戏

  • 紧接上回,我们把promise基本特点已经写完了,这篇开始写调用.then方法返回一个新的Promise实例等进阶的promise特点
  • .then方法在调用时,里面有两个函数参数(onfulfilled和onrejected),分别是在promise实例成功/失败时调用。而且这两个函数的执行是否成功,也决定着返回的新的实例的状态。只要这个两个函数执行报错,那么新实例的就会执行rejec函数,变为失败状态。
  • 还有一点就是新的promise实例的状态也取决于返回的是否是一个新的promise实例来决定
  • .then 方法如果没传第一个函数参数或者第二个函数参数,系统默认传一个函数参数,成功的函数没传的话,直接传一个返回本身,失败的函数没传,就抛出一个异常,可以供下一个.then继续执行
Promise.prototype = {
          //是否是自定义
          customize: true,
          constructor: Promise,
          // 执行then的时候,是异步执行,会返回一个新的Promise实例
           then: function (onfulfilled, onrejected) {
            //处理onfulfilled/onrejected不传值的情况
            if (typeof onfulfilled !== 'function') {
              onfulfilled = function onfulfilled(value) {
                return value;
              };
            }
            if (typeof onrejected !== 'function') {
              onrejected = function onrejected(reason) {
                throw reason;
              };
            }
			//self是原始promise实例
            var self = this;
            //promise是新的promise实例
            var promise=new Promise(function(resolve,reject){
            	switch (self.PromiseState) {
                //知道状态的情况
                case 'fullfilled':
                  setTimeout(function () {
                    try {
                      var x = onfulfilled(self.PromiseResult);
                      resolvePromise(promise, x, resolve, reject);
                      //还得判断x是不是promise实例
                    } catch (err) {
                      //报错就执行reject
                      reject(err);
                    }
                  });
                  break;
                case 'rejected':
                  setTimeout(function () {
                    try {
                      var x = onrejected(self.PromiseResult);
                      resolvePromise(promise, x, resolve, reject);
                    } catch (error) {
                      reject(error);
                    }
                  });
                  break;
                /* 
                不知道实例状态的时候(executor函数中是一个异步操作)
                此时我们应该把基于then传入的方法存起来,在执行resolve/reject函数时,通知其执行
                */
                default:
                  // self.onFulfilledCallbacks.push(onfulfilled);
                  // self.onRejectedCallbacks.push(onrejected);
                  //存放匿名函数的好处就是可以接收onfulfilled/onrejected返回值,判断其是否报错
                  self.onFulfilledCallbacks.push(function (PromiseResult) {
                    try {
                      var x = onfulfilled(PromiseResult);
                      resolvePromise(promise, x, resolve, reject);
                    } catch (error) {
                      reject(error);
                    }
                  });
                  self.onRejectedCallbacks.push(function (PromiseResult) {
                    try {
                      var x = onrejected(PromiseResult);
                      resolvePromise(promise, x, resolve, reject);
                    } catch (error) {
                      reject(error);
                    }
                  });
                  break;
              }
            })
            //返回一个新的promise实例
            return promise;
		}
}
  • 这是统一处理基于then返回新实例的成功和失败

  • 首先判断返回值和当前的创建的新实例是否一样,一样的话就会产生死循环。

  • 根据Promise A+ 规范知道,是否是一个promise实例,有几点条件

    • 必须是函数或者对象
    • 必须有.then方法
  • 这样的话,如果.then方法的两个函数参数的返回值不是一个promise实例的话,直接就把新的promise实例就变为成功态了,如果是一个promise实例,则必须判断是否满足以上的条件,然后再根据执行resolve/reject判断新的promise实例的状态

/* 
          promise:处理的那个promise实例
          x:执行onfulfilled/onrejected拿到的结果
          resolve:promsie变成功
          reject:promise变失败

         */
 //统一处理基于then返回新实例的成功和失败
        function resolvePromise(promise, x, resolve, reject) {
          //如果返回值和当前的创建的新实例一样,形成死循环
          if (x === promise) {
            throw new TypeError('Chaining cycle detected for promise #<Promise>');
          }
          if ((x !== null && typeof x === 'object') || typeof x === 'function') {
            try {
              var then = x.then;
              if (typeof then === 'function') {
                //走到这一步,返回结果一定是一个新的promsie实例
                then.call(
                  x,
                  function (y) {
                    resolve(y);
                  },
                  function (r) {
                    reject(r);
                  }
                );
              } else {
                resolve(x);
              }
            } catch (error) {
              reject(error);
            }
          } else {
            resolve(x);
          }
        }