zoukankan      html  css  js  c++  java
  • 理解co执行逻辑

    对于co的一个最简版的实现,代码如下 (https://gist.github.com/iwillwen/8488050)

    function co(generator) {
      return function(fn) {
        var gen = generator();
        function next(err, result) {
            if(err){
                return fn(err);
            }
            var step = gen.next(result);
            if (!step.done) {
                step.value(next);
            } else {
                fn(null, step.value);
            }
        }
        next();
       }
    }


    为了理解这个代码,来看一个例子

    var co = require('./co');
    // wrap the function to thunk
    function readFile(filename) {
        return function(callback) {
            require('fs').readFile(filename, 'utf8', callback);
        };
    }
    
    co(function * () {
        var file1 = yield readFile('./file/a.txt');
        var file2 = yield readFile('./file/b.txt');
    
        console.log(file1);
        console.log(file2);
        return 'done';
    })(function(err, result) {
        console.log(result)
    });

    现在就执行顺序来说明一下

    1. 首先是以下部分
     co(function * () {
            var file1 = yield readFile('./file/a.txt');
            var file2 = yield readFile('./file/b.txt');
    
            console.log(file1);
            console.log(file2);
            return 'done';
        })

       这部分代码执行了co函数,并把function*()作为参数generator传入,也就是说,整个部分变成了

    function(fn) {
        var gen = generator();
        function next(err, result) {
            if(err){
                return fn(err);
            }
            var step = gen.next(result);
            if (!step.done) {
                step.value(next);
            } else {
                fn(null, step.value);
            }
        }
        next();
       }(function(err, result) {
        console.log(result)
    })

      这个部分执行这个function,并把

    function(err, result) {
      console.log(result) }

      作为fn的实参传入。

      2. 执行过程中,`var gen`为 `function *()`部分,下面是函数`next()`的声明,之后执行了`next()`函数,此时的`err`和`result`均为空。

      3. `err`为空,因此`if(err)`不执行,执行 `var step = gen.next(result);`,由于`result`这里为空,因此

    var step = gen.next(result)
    step.value
    =readFile('./file/a.txt')
    =function(callback) {
            require('fs').readFile('./file/a.txt', 'utf8', callback);
       };

      4. `step.done `为`false`, 执行`step.value(next);`,即执行

    function(callback) {
        require('fs').readFile('./file/a.txt', 'utf8', callback);
    };

      函数,并`next`作为`callback`传入。`readFile`传入回调函数的参数为`err`和`data`,因此在读取完文件后,`err`和a文件的内容(作为result的实参)传入了 `next`函数并执行。

      5. 与2,3类似,执行`var step = gen.next(result)`,这一步由于result的值为a文件的内容,因此`file1`被赋值为a文件的内容(next方法可以带一个参数,该参数就会被当作上一个yield语句的返回值。)。与4类似,err和b文件的内容(作为result的实参)传入`next`函数并执行。

      6. 再次执行到`var step = gen.next(result)`的时候,`file2`被赋予文件b的内容,由于`generator`下面没有`yield`了,于是执行到`return`,`step.value='done'`,`step.done=true`,函数从上次yield语句停下的地方,一直执行到return语句(如果没有return语句,就执行到函数结束)。(next方法返回的对象的value属性,就是紧跟在return语句后面的表达式的值(如果没有return语句,则value属性的值为undefined),done属性的值true,表示遍历已经结束。)

      7. 执行`fn(null, step.value);` 即

    function(err, 'done') {
        console.log('done');
    }();

      8. 因此代码的执行结果为

      content in a.txt

      content in b.txt

      done

  • 相关阅读:
    1093 Count PAT's(25 分)
    1089 Insert or Merge(25 分)
    1088 Rational Arithmetic(20 分)
    1081 Rational Sum(20 分)
    1069 The Black Hole of Numbers(20 分)
    1059 Prime Factors(25 分)
    1050 String Subtraction (20)
    根据生日计算员工年龄
    动态获取当前日期和时间
    对计数结果进行4舍5入
  • 原文地址:https://www.cnblogs.com/yuanting0505/p/4633715.html
Copyright © 2011-2022 走看看