对generator的一些总结

237 阅读3分钟

特点一、generator是一个生产器,生成器的作用是返回一个迭代器。

    function* read(){
        yield 'node';         // yield 产出
        yield 'javascript';
    }
    let a = read();
    console.log(a);  //Object [Generator] {}
    console.log(a.next()); // {value:"node",done:false}
    //调用next()方法才会往下执行。

特点二、错误异常的捕获。支持try、catch捕获异常

    function* read() {          //generator生成器
        try {
            yield 'node';          
            yield 'javascript';
        }catch (e) {
            console.log(e);
        }
    }
    if(a.next().value === 'node'){
        a.throw("异常错误了");
    }
    //要想触发catch捕获异常需要手动调用迭代器的throw方法抛出异常。

特点三、特殊的传参。

    function* read(){
        try{
            let q = yield 'node';
            console.log(q);
            let w = yield 'javascript';
            console.log(w);
        }catch(e){
            console.log(e);
        }
    }
    let p = read();
    p.next(); //此时不会执行打印q因为,每一次next只是走到当前的yield就会停止
    p.next(); //此时q打印的为undefined,因为q获取的是next()方法执行时的参数会被作为yield的返回值。
    p.next(12); //此时w打印的值为12,参数12被作为yield的返回值赋值给w所以此时的w是有值的。并且,第一个next传入的参数是没有实际意义的。因为第一个next()执行的时候,前面没有yield所以无法作为返回值返回。

如何将一个genertor函数的内容放置到另一个genertor里面?

    function* a(){
        yield 1;
        yield 2;
    }
    function* b(){
        yield 3;
        yield 4;
    }
    //以下写法可以认为将a方法的内容放置在b里面去执行
    function* b(){
        yield * a()
        yield 3;
        yield 4;
    }
    let c = b();
    console.log(c.next());
    console.log(c.next());
    console.log(c.next());
    console.log(c.next());
    console.log(c.next());

扩展实现一个co库(CO库是为了解决不停的调用next方法而写的一个库使用方法和实现如下)

function* read() {
    try{
       let a = yield '1';
       let b = "今年"+a+"岁了";
       return b; 
    }catch(e){
        console.log(e);  
    }
    
}
//使用方法、安装一个CO库引入,将generator函数传入然后会返回一个promise。直接then即可
//这里将自己实现一个co库如下。
co(read()).then(data=>{
    console.log(data);
});
//co实现
function co(it) {
    return new Promise((resolve,reject)=>{                   // 1
        function next(data) {                                // 2
            let { value , done} = it.next(data);             // 3
            if(done){                                        // 4
                resolve(value);                              // 5
            }else{                                           // 6
                Promise.resolve(value).then(data=>{          // 7
                    next(data);                              // 8
                },err=>it.throw("失败了"));                  // 9
            }
        }
        next()                                               //12
    })
}
/*
 因为co返回值可以then调用说明返回的是一个promise。所以,第一行直接返回一个promise
 第二行将next封装成一个独立的方法,为的是可以在内部实现递归调用。
 第三行是一个赋值结构,拿到it.next()的执行结果跟read方法是否执行完的信息。参数是拿到上一个yeild的返回值,第一次执行时没有传参为undefined,其实也没有关系,反正第一次的传参不会被方法使用。见上文特点三
 第四行判断当前是否执行完毕,如果是直接在第五行让当前的promise成功即可。
 第六行如果没有执行完毕。继续执行,因为此时的value可能是一个promise也可能是一个基础数据的值。所以使用第七行的promise.resolve包装,这样,假如value是一个promise那么会等待当前的promise执行完成拿到返回值。如果value不是一个promise就将它变成一个promise。
 第八行将最终的value传入next中作为yeild的返回值递归执行。
 第九行,执行异常的时候抛出异常信息。见特点二
 第十二行,启动next的第一次执行
 
*/