美文网首页编程go之Nodejs
Koa基础 thunkify与co如何实现对Generator函

Koa基础 thunkify与co如何实现对Generator函

作者: 编程go | 来源:发表于2017-07-09 21:49 被阅读22次

    thunkify reposiroty 实现Generator 自动执行

    thunkify 是自动执行 Generator 函数的一种方法,出自业界大神TJ

    • Javascript 的Thunk 函数

    在 JavaScript 语言中,Thunk是将多参数函数,将其替换成一个只接受回调函数作为参数的单参数函数。

    如下面的Demo,

    const fs = require('fs');
    const path = require('path');
    const fpath = path.join(__dirname, 'a.txt');
    
    var Thunk = function(fileName) {
        return function(callBack) {
            return fs.readFile(fileName, callBack);
        }
    }
    var readFileThunk = Thunk(fpath);
    readFileThunk(function(err, data) {
        if (err) console.log(`${err}`);
        else console.log(`${data}`);
    })
    

    上面的示例代码中自定义了Thunk 函数,
    当var readFileThunk = Thunk(fpath)时,
    其实代码返回的是函数
    function(callBack) {
    return fs.readFile(fileName, callBack);
    }

    thunk流程图.jpg

    这只是我自己实现的Thunk 函数,我们一起看看npm 第三方库的thunkify

    • thunkify 库核心代码
    function thunkify(fn) {
    
      // thunkify 直接返回就是数组
      return function() {
        // 收集arguments 的参数,保存在临时数组中。
        var args = new Array(arguments.length);
        var ctx = this;
    
        for (var i = 0; i < args.length; ++i) {
          args[i] = arguments[i];
        }
    
        return function (done) {
          var called;
          // 将回调函数加载到上一级收集的参数数组的末尾。
          args.push(function () {
            // 确保回掉函数只会被加载一次。
            if (called) return;
            called = true;
            done.apply(null, arguments);
          });
    
          try {
            fn.apply(ctx, args);
          } catch (err) {
            done(err);
          }
        }
      }
    };
    
    var fs = require('fs');
    var read = thunkify(fs.readFile);
    read('package.json', 'utf8')(function(err, str){
    });
    

    与我的Demo在原理上很相似,但是大神的代码严谨性更好,感觉被虐狗了。

    • Thunk 函数有什么作用?

    情景:如果我们想从一个文件中读取文件,然后在将读取的内容写入到另一个文件中。读文件是异步的,这时我们要阻塞线程,才能保证存入到新文件的内容是刚才读取的内容。

    const fs = require('fs');
    const thunkify = require('thunkify');
    const path = require('path');
    const fpath1 = path.join(__dirname, './test1.txt');
    const fpath2 = path.join(__dirname, './test2.txt');
    
    var readFileThunify = thunkify(fs.readFile);
    var writeFileThunify = thunkify(fs.writeFile);
    var gen = function *() {
        var data = yield readFileThunify(fpath1);
        yield writeFileThunify(fpath2, data);
    }
    
    var g = gen();
    g.next().value((err, data)  => {
        if (err) console.log(`${err}`);
        else {
            console.log(`${data}`);
            // 将读取到的内容传给写入文件的方法中
            g.next(data).value((err, data) => {
                if (err) console.log(`${err}`);
                else console.log(`${data}`);
            })
        }
    })
    

    co repository - 基于Promise自动执行Generator对象

    Generator based control flow goodness for nodejs and the browser, using promises, letting you write non-blocking code in a nice-ish way.
    官方介绍

    • co 的特点
    1. 回调函数。将异步操作包装成 Thunk 函数,在回调函数里面交回执行权。
    2. Promise 对象。将异步操作包装成 Promise 对象,用then方法交回执行权。

    以下是我通过thunk函数和Promise对象实现的简易generaor对象手动执行器

    /**
     * Generator 函数体
     */
    const fs = require('fs');
    const path = require('path');
    var fpath1 = path.join(__dirname, './test1.txt');
    var fpath2 = path.join(__dirname, './test2.txt');
    
    function readFileFun(fpath) {
        return new Promise(function(resolve, reject){
            fs.readFile(fpath, function(err, result) {
                if (err) reject(err);
                else resolve(result);
            });
        });
    }
    
    var gen = function *() {
        //yield 后是一个promise对象
        var content1 = yield readFileFun(fpath1); 
        var content2 = yield readFileFun(fpath2);
        console.log(`${content1}`); 
        console.log(`${content2}`); 
    }
    
    /**
     * manual perform generator.
     */
    var g = gen();
    g.next().value.then((data) => {
        // 通过next() 函数向generator 函数体传值
        g.next(data).value.then((data1) => {
            g.next(data1);
        })
    })
    

    下面是我写的简易自动化执行器

    /**
     * automatic perform generator.
     */
    var preCO = require('./preCOGenerator');
    
    function run(gen) {    
        var g = gen()
        function next(data) {
            var result = g.next(data);
            // 如果generator 遍历结束,直接返回值。
            if (result.done) return result.value;
            // 通过then() 获取Promise 对象的返回值。
            result.value.then(data => {
                // 递归调用next()
                next(data)
            })
        }
        next();
    }
    
    run(preCO.gen);   
    
    • co 库核心代码
      有兴趣点击co后自行查阅, 原理与我的简易版大同小异,但是菜鸟与大师的差异在于细节。

    相关文章

      网友评论

        本文标题:Koa基础 thunkify与co如何实现对Generator函

        本文链接:https://www.haomeiwen.com/subject/amgshxtx.html