• Generator函数(二)


    for...of循环

    1.for...of循环可以自动遍历Generator函数,不需要再调用next方法

    function* helloWorldGenerator(){
        yield 'hello';
        yield 'world';
        return 'ending';
    }
    for (let f of helloWorldGenerator()){
        console.log(f);//'hello','world'
    }
    
    var hw = helloWorldGenerator();
    hw.next();
    hw.next();//done的值是false
    hw.next();//done的值是true,所以此时不会再输出ending
    

    这里使用for...of循环和next()方法遍历Generator函数,在使用for...of循环可以自动遍历Generator函数,且此时不再需要调用next方法。
    而且遍历出来的结果也不同。
    2.前面章节介绍过,for...of循环,扩展运算符(...),解构赋值和array.from方法内部调用的都是遍历器接口。这就是说,他们可以将Generator函数返回的Iterator对象作为参数。

    function* numbers(){
        yield 1;
        yield 2;
        return 3;
        yield 4;
    }
    
    [...numbers()];//[1,2],扩展运算符(...)
    Array.from(numbers()) //[1,2],Array.from方法
    let [x,y] = numbers(); //解构赋值
    x//1
    y//2
    
    for(let n of numbers()){
        console.log(n);
    }
    //1
    //2
    

    3.使用Generator函数和for...of循环为原生的JavaScript对象加上遍历接口

    function* objectEntries(obj){
        let propKeys = Reflect.ownKeys(obj);//获取一个对象obj的key
        for(let propKey of propKeys){
            yield [propKey,obj[propKey]];
        }
    }
    let jane = {first:'jane',last:'Doe'};
    for(let [key,value] of objectEntries(jane)){
        console.log(`${key}:${value]`);
    }
    // first:jane
    // last:Doe
    

    第二种方法实现添加遍历接口

        function* objectEntries(obj){
            let propKeys = Reflect.ownKeys(obj);
            for(let propkey of propKeys){
                yield [propkey,obj[propkey]];
            }
        }
        let jane = {first:'jane',last:'doe'};
        jane[System.iterator] = objectEntries;
        for(let [key,value] of jane){
            console.log(`${key}:${value}`);
        }
        //  first:jane
        //  last:doe
    

    Generator.prototype.throw()

    1.Generator函数返回的遍历器都有一个throw方法,可以在函数体外抛出错误,在函数体内捕获错误。

    var g = function* (){
        while (true ){
            try{
                yield;
            }catch (e){
                if(e != 'a') throw e;
                console.log('内部捕获',e);
            }
        }
    };
    var i = g();
    i.next();
    
    try{
        i.throw('a');
        i.throw('b');
    }catch(e){
        console.log('外部捕获',e);
    }
    //内部捕获 a
    //外部捕获 b
    

    总结一下,有几种错误抛出和捕获的情况。
    (1)Generator函数体内有try...catch块,函数体外也有try...catch块,如果函数体外用多个throw方法抛出错误:
    解决错误的情况:第一个throw方法,将被函数体内的捕获,后面的throw方法会被函数体外的捕获。(因为Generator函数内部的catch语句已经执行过了,不会再捕获到后面的throw方法抛出的错误)
    (2)Generator函数体内和体外都有try...catch块,如果函数体外用throw命令抛出错误:
    解决情况:因为用throw命令抛出的错误,只能被函数体外的catch捕获,即使函数体内有catch块。
    (3)Generator函数体内没有try...catch块,函数体外有try...catch块,如果函数体外用throw方法或者throw命令抛出错误:
    解决情况:被外部的try...catch块捕获。
    (4)Generator函数体内和体外都没有try...catch块,那么如果抛出错误:程序会报错,直接中断执行。

    2.关于Generator函数体内有无try...catch块,会不会影响到遍历器的状态,即关系到next方法会不会被正常执行。
    如果Generator函数体内没有try...catch块,则遍历器的throw方法抛出的错误不会影响到下一次的遍历,否则遍历直接终止,但是如果用的是throw命令,则不会影响到遍历器的状态。

    var gen = function* gen(){
        yield console.log('hello');
        yield console.log('world');
    }
    
    var g = gen();
    g.next();
    try {
        g.throw();
    }catch(e){
        g.next();
    }
    //hello
    

    虽然Generator函数内部没有部署try...catch块,那么throw方法抛出的错误即使会被外部的try...catch代码块捕获。
    但是第二次调用next()方法的时候遍历器状态已经变成终止了。但是使用throw命令(throw new Error())抛出的错误就不会影响到遍历器的状态,即next()方法。
    3.Generator函数这种函数体内捕获错误的机制大大方便了对错误的处理。如果使用回调函数,想要捕获多个错误的话,就不得不为每个函数写一个错误处理语句。
    但是使用Generator函数就会简化很多,例如

        function* g(){
            try{
                var a = yield foo('a');
                var b = yield foo('b');
                var c = yield foo('c');
            }catch (e){
                 console.log(e);
            }
            console.log(a,b,c);
        }
    

    4.Generator函数体内抛出的错误也可以被函数体外的catch捕获。

        function* foo(){
            var x = yield 3;
            var y = x.toUpperCase();//这里报错
            yield y;
        }
        var it = foo();
         it.next();
    
        try{
            it.next(42);
        }catch(err){
            console.log(err);//这里捕获
        }
    
  • 相关阅读:
    批量插入测试脚本
    Show Profile分析sql语句的资源消耗
    慢查询日志
    ORDER BY优化
    Join查询
    Explain(执行计划)分析
    索引
    MySQL中的DML(数据操作语言)和DQL(数据查询语言)
    MySQL中的DDL(数据定义语言)和DCL(数据控制语言)
    MySQL架构体系介绍
  • 原文地址:https://www.cnblogs.com/sminocence/p/7274984.html
Copyright © 2020-2023  润新知