• co源码解读


    最近在学习使用Koa.在看官网的例子的时候时候看到它的中间件的级联模式是通过生成器实现的,之后了解到Koa的级联是通过Co这个库实现的,下面就是对这个库的代码的主要流程的部分解读

    1.生成器基础

    2.代码解读

    1.生成器基础

    这个是infoq的深入浅出ES6中生成器的一章   生成器基础

    可以通过下面的代码片段去大致的理解Co函数的执行过程  生成器可以通过next来实现任务的串行执行  next方法返回一个对象 有value属性(yield执行的值) done 是否还有未执行的yield逻辑 同时还能将参数通过next进行传递 供下面的逻辑调用

    function *test() {
        var x = yield 1;
        yield console.log(x);
    }
    
    var a = test();
    var temp = a.next();
    a.next(temp.value)  //1
    View Code

    2. 代码解读部分

    function objectToPromise(obj){
      var results = new obj.constructor();
      var keys = Object.keys(obj);  //Object.keys()返回一个对象所有可枚举属性的数组
      var promises = [];//保存对象中promise运行的结果
      for (var i = 0; i < keys.length; i++) {
        var key = keys[i];//
        var promise = toPromise.call(this, obj[key]);
        if (promise && isPromise(promise)) defer(promise, key);//将原对象属性中Promise的与数组关联
        else results[key] = obj[key];
      }
      return Promise.all(promises).then(function () {
        return results;
      });//Promise接受一个Promise对象的数组作为参数 当数组里面全部变成resolve或者reject状态
    
      function defer(promise, key) {
        // predefine the key in the result
        results[key] = undefined;
        promises.push(promise.then(function (res) {
          results[key] = res;   //romise的then方法不仅仅是注册resolve的回调 还会将回调函数的返回值进行变换 返回promsie
          对象
        }));
      }
    }
    View Code

     Co将中间的结果和函数都进行了Promise的封装  主要看下这个objectToPromise(obj)  功能就是将一个对象转换为Promise对象 这里需要理解这两个方法 Promise.all  它接受一个Promsie数组 当数组中全部为resolve时,它就变成resolve,当其中有一个出现reject的时候,就进入reject状态。可以通过下面的代码简单的理解它的使用

    var promise1 = new Promise(function(resolve,reject){
        resolve(1);
    });
    var promise2 = new Promise(function(resolve,reject){
        resolve(2);
    });
    Promise.all([promise1,promise2]).then(function(){
        console.log('ok');
    });
    View Code

    接下来说说这个defer(promise,key) 它的功能就是将原来对象的值装换为promise之后,通过数组的方式传递给外部

      function defer(promise, key) {
        // predefine the key in the result
        results[key] = undefined;
        promises.push(promise.then(function (res) {
          results[key] = res;   promise的then方法不仅仅是注册resolve的回调 还会将回调函数的返回值进行变换 返回promsie
          对象
        }));
      }
    View Code

    promise.then  这个方法是返回一个Promise对象 这样通过then方法将所有键值的执行结果都转换为Promsie对象 在通过数组的方式传递给外部 当所有键值执行都为resolve的时候 就将整体的结果返回给外部 也就完成了对obj对象的封装。

    下面就来理解下Co函数

    function co(gen) {
      var ctx = this;
      var args = slice.call(arguments, 1);
    
      // we wrap everything in a promise to avoid promise chaining,
      // which leads to memory leak errors.
      // see https://github.com/tj/co/issues/180
      return new Promise(function(resolve, reject) {
        if (typeof gen === 'function') gen = gen.apply(ctx, args);
        if (!gen || typeof gen.next !== 'function') return resolve(gen);
    
        onFulfilled();
    
        /**
         * @param {Mixed} res
         * @return {Promise}
         * @api private
         */
    
        function onFulfilled(res) {
          var ret;
          try {
            ret = gen.next(res);
          } catch (e) {
            return reject(e);
          }
          next(ret);
          return null;
        }
    
        /**
         * @param {Error} err
         * @return {Promise}
         * @api private
         */
    
        function onRejected(err) {
          var ret;
          try {
            ret = gen.throw(err);
          } catch (e) {
            return reject(e);
          }
          next(ret);
        }
    
        /**
         * Get the next value in the generator,
         * return a promise.
         *
         * @param {Object} ret
         * @return {Promise}
         * @api private
         */
         //co函数的核心就是这个next理解 通过next传递将上一个generator执行的结果往下传递并且进行了Promise的封装
        function next(ret) {
          if (ret.done) return resolve(ret.value);
          var value = toPromise.call(ctx, ret.value);
          if (value && isPromise(value)) return value.then(onFulfilled, onRejected);
          return onRejected(new TypeError('You may only yield a function, promise, generator, array, or object, '
            + 'but the following object was passed: "' + String(ret.value) + '"'));
        }
      });
    }
    View Code
     

    参考  Generator与异步编程   Co

     
  • 相关阅读:
    python 线程 进程 标识
    创建2600个文件 批量创建文件 文件夹
    Do not use the <section> element as a generic container; this is what <div> is for, especially when the sectioning is only for styling purposes.
    js json
    大量陈旧进程的批量杀死
    positive 相对其正常位置,那什么是正常位置: 请问调试,请问浏览器
    CSS3 弹性盒子(Flex Box) 微信小程序图片通栏
    SHOW PROCESSLIST Syntax
    How MySQL Opens and Closes Tables refuse connections 拒绝连接的原因 file descriptors
    1250太小了 mysql 并发
  • 原文地址:https://www.cnblogs.com/tiantianwaigong/p/6441723.html
Copyright © 2020-2023  润新知