理解co库的流程控制

Co库使用promises和generator生成器为nodejs和浏览器优化控制流的结构,让你以一种类似于同步的方式编写非阻塞代码

2 min read
By myfreax
理解co库的流程控制

Co库使用promises和generator生成器为nodejs和浏览器优化控制流的结构,让你以一种类似于同步的方式编写非阻塞代码

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

简单版本的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;
          //调用generators后返回的是可遍历的迭代器,迭代器中next的方法返回的是一个对象{done:false,value:1},
          //对象的done属性的是布尔值表示遍历是否结束
        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);
              //调用generators后返回的是可遍历的迭代器,迭代器中next的方法返回的是一个对象{done:false,value:1},
              //对象的done属性的是布尔值表示遍历是否结束
            //判断是否是Promise,如果是promise则执行promise再进入next递归遍历generator.next
            if (isPromise(result.value))return result.value.then(res => {
                let result;
                try {
                    result = gen.next(res); 
                }catch (e){
                    return reject(e);// generator运行时的错误,捕获后由交给promise处理返回外部处理
                }
                next(result)
            }, err => {
                let result;
                try {
                    //Generator函数返回的遍历器对象,都有一个throw方法,
                    //可以在函数体外抛出错误,然后在Generator函数体内捕获。
                    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);
});