• Generator函数(一)


    Generator函数是ES6提供的一种异步编程解决方案,语法行为与传统函数完全不同。对于这个函数有多种理解。从语法上来理解,可以将它理解成一个状态机,封装了多个内部状态。内部的不同状态是通过yield语句来定义不同的内部状态,return语句也可以看成一个状态。

    基本概念

    执行Generator函数会返回一个遍历器对象。

    //ES6没有规定function关键字与函数名之间的星号写在哪个位置
    function* helloWorldGenerator(){
    	yield 'hello';
    	yield 'world';
    	return 'ending';
    }
    
    var hw = helloWorldGenerator();
    

    这个函数的调用方式和普通函数一样来调用,调用这个函数,并不执行,返回的也不是函数运行的结果,而是一个指向内部状态的指针对象,也就是一个遍历器对象。
    下一步,必须调用next方法,使得指针移向下一个状态。也就是说,每次调用next方法,内部指针就从函数头部或上一次停下来的地方开始执行,直到遇到下一条yield语句(或return语句)为止,
    调用next()方法,会返回一个包括value属性和done属性的一个对象。

    hw.next();
    // {value:'hello',done:false}
    //这个value的值就是yield语句的值,done属性的值false表示遍历还没有结束
    hw.next();
    // {value:'world',done:false}
    hw.next();
    //{value:'ending',done:true};
    hw.next();
    //{value:undefined,done:true};
    

    换言之,Generator函数是分段执行的,yield语句是暂停执行的标记,而next方法可以恢复执行。
    注意:Generator函数返回的是一个遍历器对象,代表Generator函数的内部指针,以后每次调用这个函数,都会返回带有value和done两个属性的一个对象、

    yield语句

    1.实际上yield语句是一个暂停标志。
    2.yield语句和return语句在Generator函数中的区别
    (1)yield语句可以在这个函数中执行多次,我的理解就是,在编写这个函数的时候,可以写多条yield语句,而return语句只能有一条。
    (2)yield语句可以使Generator函数获取到多个值,即生成一系列的值。
    (3)yield语句可以暂停执行,当执行next方法的时候,可以使函数从上一句yield语句停下的地方开始执行,直到下一个yield语句。而return没有位置记忆功能。
    需要注意的是,yield语句后面的表达式,只有当调用next方法、内部指针才会指向该语句时才会执行,因此等于为JavaScript提供手动的“惰性求值”的语法功能。

        function* gen(){    
                yield 123+456;
        }
    

    3.Generator函数也可以不用yield语句,这时候变成了一个单纯的暂缓执行函数。

    function* f(){
        console.log("ffff");
    }
    
    var generator = f();
    
    setTimeout(function(){
        generator.next();
    },2000);
    

    4.还有需要注意的是,yield语句不能用在普通函数中,否则会报错。

    var arr = [1,[[2,3],4],[5,6]];
    var flat = function* (a){
        a.forEach(function(item){
            if(typeof item !== 'number'){
                yield* flat(item);
            }else{
                yield item;//这里面不应该使用yield,因为forEach的参数是一个普通函数。
            }
        })
    };
    
    //解决这个错误的方法有
    将forEach改为for循环
    
    var arr = [1,[[2,3],4],[5,6]];
    var flat = function* (a){
        var length = a.length;
        for(var i=0;i<length;i++){
            var item = a[i];
            if(typeof item !== 'number'){
                yield* flat(item);
            }else{
                yield item;
            }
        }
    }
    
    for(var f of flat(arr)){
        console.log(f);
        //1,2,3,4,5,6
    }
    

    5.yield语句用在表达式中,必须要用括号括起来。
    6.yield用在函数参数或者是赋值等式的右边时,不需要用括号。

    next方法的参数

    1.yield语句本身没有返回值,要有值,也是undefined。所以为了赋予yield语句值,所以就让next方法有了参数。
    2.next方法有了参数之后,因为Generator函数需要调用next方法来返回yield语句后面的值,这时候调用有参数的next方法之后,这个参数就会被当做上一个yield语句的返回值,注意是yield语句的返回值,而不是yield后面的值。
    3.之前说了yield语句可以用于表达式中,所以有参的next方法可以为表达式中的yield语句传值。

    function* foo(x){
        var y = 2*(yield(x+1));
        var z = yield(y/3);
        return (x+y+z);
    }
    
    var a = foo(5);
    a.next();// {value:6,done:false}
    a.next(12) // {value:8,done:false}
    a.next(13) // {value:42,done:true}
    

    4.注意:由于next方法的参数表示的是上一条yield语句的返回值,所以第一条next语句默认没有参数,V8引擎直接忽略第一次使用next方法时的参数,从语义上来说,第一个next方法用来启动遍历器对象,所以不用带参数。
    但是如果实在想在第一条语句中传参,并且能够有输入值,可以在Generator函数外面包一层,相当于先在这个包裹的这一层执行next()方法,用来启动遍历器对象。

    //定义一个普通的函数,用来包裹Generator函数。
    function wrapper(generatorFunction){
        return function(...args){
            let generatorObject = generatoraFunction(...args);
            generatorObject.next();//先执行这个next
            return generatorObject;
        }
    }
    
    const wrapped = wrapper(function* (){
        console.log(`First input:${yield}`);
        return 'DONE';
    })
    wrapped.next('hello');//First input: hello,再执行这个next,并把hello这个值赋给yield
    
  • 相关阅读:
    Java HashMap的原理、扩容机制、以及性能
    Istanbul BFT共识算法解读
    golang中slice的扩容机制
    Use the "Enclave Signing Tool" to sign enclave files
    以太坊椭圆曲线Specp256k1通过消息的hash和签名(对消息的hash的签名)来恢复出公钥和计算r值
    Intel SGX SDK toolkits
    Intel SGX Edger8r
    Intel SGX C++ library
    SGX Makefile学习笔记
    在ubuntu中安装gem5
  • 原文地址:https://www.cnblogs.com/sminocence/p/6928999.html
Copyright © 2020-2023  润新知