V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
huangyanxong
V2EX  ›  Node.js

理解 Co 库的源码

  •  
  •   huangyanxong · 2016-12-13 11:58:17 +08:00 · 1877 次点击
    这是一个创建于 2689 天前的主题,其中的信息可能已经有所发展或是发生改变。

    Co 流程流程控制器源码与理解,index.js 包含理解和注释

    简单版本的 Co 库

    这个版本是重点是理解 generator 工作原理

    // @flow
    /**
     * Created by Freax on 16-12-12.
     * @Blog http://www.myfreax.com/
     */
    function co(generator) {
        let gen = generator();
        next(gen.next()); //递归遍历 generator.next
        function next(result) {
            if (result.done)return null;//如果 generator 执行完毕,直接解决退出遍历
            let res = gen.next(result.value);
            next(res);
        }
    }
    
    co(function *gen() {
        let a = yield 1;
        console.info(a, 'a');
        let b = yield 2;
        console.info(b, 'b');
        let c = yield 3;
        console.info(c, 'c');
    });
    

    generator+promise Co 库的简版

    理解 generator+promise 如何工作

    // @flow
    /**
     * Created by Freax on 16-12-12.
     * @Blog http://www.myfreax.com/
     */
    
    function isPromise(obj) {
        return typeof obj === 'object' && 'function' == typeof obj.then;
    }
    
    function co(generator) {
        return new Promise((resolve,reject)=>{
            let gen = generator();
            next(gen.next());
            function next(result) {
                if (result.done)return resolve(result.value);//如果 generator 执行完毕,直接解决退出遍历
                //判断是否是 Promise ,如果是 promise 则执行 promise 再进入 next 递归遍历 generator.next
                if (isPromise(result.value))return result.value.then(res => {
                    let result;
                    try {
                        result = gen.next(res); //抛出 generator 的错误
                    }catch (e){
                        return reject(e);// 捕获后由交给 promise 处理返回外部处理
                    }
                    next(result)
                }, err => {
                    let result;
                    try {
                        result = gen.throw(err); //yield 返回 promise 进入 reject 后的错误,抛出 generator 的错误
                    }catch (e){
                        return reject(e); // 捕获后由交给 promise 处理返回外部处理
                    }
                    next(result)
                });
                let res = gen.next(result.value);
                next(res);
            }
        });
    
    }
    
    co(function *gen() {
        let a = yield Promise.resolve(1);
        console.info(a, 'a');
        let b = yield 2;
        console.info(b, 'b');
        let c = yield 3;
        console.info(c, 'c');
    
    }).catch((err)=>{
        console.info(err);
    });
    

    Github 欢迎提交 PR or ISSUE

    iugo
        1
    iugo  
       2016-12-13 14:29:34 +08:00
    我对此有点模糊.

    不过想要全面理解 generators 还是要先理解 iterators.
    huangyanxong
        2
    huangyanxong  
    OP
       2016-12-13 19:07:30 +08:00
    @iugo generator 调用 generators 后返回的是可遍历迭代器,这个迭代器有个 next 的方法,方法返回的是一个对象{done:false,value:1},对象的 done 属性的 true 代表已经遍历完毕
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   3253 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 13:38 · PVG 21:38 · LAX 06:38 · JFK 09:38
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.