zoukankan      html  css  js  c++  java
  • 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);
    });
    
  • 相关阅读:
    zabbix验证微信
    free
    有名管道和无名管道
    shell实现并发控制
    TCP/IP协议簇 端口 三次握手 四次挥手 11种状态集
    自动化运维
    JSON对象(自定义对象)
    对象中属性的遍历、删除与成员方法
    对象间的赋值操作
    自定义类
  • 原文地址:https://www.cnblogs.com/jianjie/p/13877799.html
Copyright © 2011-2022 走看看