• Generator函数的语法


    简介

    Generator函数是ES6关于异步编程的解决方案。Generator函数能够让函数暂停执行(即交出函数的执行权),简单直白点来理解,Generator函数就是一个状态机,内部封装了多个状态(暂停执行的位置)

    • 定义:
    1. function 关键字后有一个*
    2. 函数体内部有yield表达式,表示暂停的位置,定义不同状态。
    function* helloWorld(){
        yield 'hello';
        yield 'world';
        return 'end';
    }
    var hw = helloWorld();
    
    • 调用
    1. 通过next()方法调用,返回结果形如{value:xxx, done: bool}。并在下一个yield处暂停。
    2. 当函数执行完毕(碰到return或者所有yield执行完毕),那么返回的结果value为return的值(无return 则返回undefined),done为true。
    3. 函数执行完毕后无论怎么调用next()方法,结果都是{ value: undefined, done: true }
    4. 通过next()可以传入参数进入状态机,即传入值取代yield表达式。
    hw.next();
    //{value:'hello',done:false}
    hw.next();
    //{value:'world',done:false}
    hw.next();
    //{value:'end',done:true}
    hw.next()
    //{value:'undefined',done:true}
    
    • yield*表达式
      yield*表达式用于在Generator函数内部调用另外一个Generator函数。

    • throw()方法
      在函数体外部抛出错误,如果内部有catch语句,那么优先内部捕获,否则为外部捕获。全局的throw命令只能够外部catch捕获

    • return()方法
      用于终结遍历Generator函数。Generator函数调用return方法后,那么返回值的done变为true,遍历终止。
      当内部有try...finally代码块时,return会推迟到finally代码块执行完后再执行。

    function* numbers () {
      yield 1;
      try {
        yield 2;
        yield 3;
      } finally {
        yield 4;
        yield 5;
      }
      yield 6;
    }
    var g = numbers();
    g.next() // { value: 1, done: false }
    g.next() // { value: 2, done: false }
    g.return(7) // { value: 4, done: false }
    g.next() // { value: 5, done: false }
    g.next() // { value: 7, done: true }
    
    • 其他
    1. yield只能在Generator函数内使用
    2. Generator函数执行后会返回一个遍历器对象,通过把Generator函数赋值给对象的Symbol.iterator属性,即可使对象获得Iterator接口,可以被for...of...等遍历

    应用

    1. 利用Generator遍历Object的属性

    function* objectEntries(obj) {
      let propKeys = Reflect.ownKeys(obj);
      
      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}`);
    }
    

    2. 利用yield*遍历嵌套数组

    let arr = [1,2,[3,4,5,[6,7,8],9],10];
    
    function* iterArr(arr){
    	for(let value of arr){
    		if(Array.isArray(value)){
    			yield* iterArr(value);
    		}else{
    			yield value;
    		}
    	}
    }
    for(let x of iterArr(arr)){
    	console.log(x);
    }
    

    3. 利用yield*中序遍历完全二叉树

    //节点的构造函数
    
    function Node(left, value, right){
    	this.left = left;
    	this.value = value;
    	this.right = right;
    }
    //完全二叉树遍历函数
    function* inorder(node){
    	if(node){
    		yield* inorder(node.left);
    		yield node.value;
    		yield* inorder(node.right);
    	}
    }
    
    //二叉树生成函数
    function binaryTree(arr){
    	if(arr.length === 1){
    		return new Node(null, arr[0], null);
    	}
    	return new Node(binaryTree(arr[0]),arr[1],binaryTree(arr[2]));
    }
    
    let tree = binaryTree([[['a'], 'b', ['c']], 'd', [['e'], 'f', ['g']]]);
    
    console.log(tree);
    
    let result = [];
    for (let node of inorder(tree)){
    	result.push(node);
    }
    console.log(result);
    

    4. Generator函数的状态机实现

    Generator 的确是用来实现状态机的最佳数据结构。

    首先,在没有外部输入的情况,一个状态机只有内部既定的逻辑,与Generator函数一样:若未经处理,那么也是一个按照既定顺序执行的多阶段的任务队列。

    通过yield 可以表示状态机的状态,利用yield来接受外界对Generator的输入,即状态机接受外部的输入参数。
    然后通过内部的逻辑,将之切换到不同的下一个yield,即可实现状态机的切换。

    提供一个利用Generator函数实现的简单状态机案例:

    • 状态机的状态变化如下图所示:

    • Generator函数模拟
    let machine = function* (){
    	let states = ['初始化','状态一', '状态二', '状态三', '状态四', '退出'];
    	let i = 0;
    	let input = yield states[0];
    	while(true){
    		if(typeof input !== 'number'){
    			input = 0;
    		}
    		switch (i) {
    			case 1:
    				if(input <= 0) i = 3;
    				else if(input > 10) i = 2;
    				else if(input > 100) i = 4;
    				break;
    
    			case 2:
    				if(input > 10) i = 4;
    				break;
    			case 3:
    				if(input > 10) i = 4;
    				else if(input < 0) i = 1;
    				break;
    			case 4:
    				if(input > 100) i = 1;
    				if(input < -100){
    					yield states[5];
    					return '状态机关闭';
    				}
    				break;
    			default:
    				i = 1;
    				break;
    		}
    		input = yield states[i];
    	}
    };
    machine = machine();
    console.log(machine.next());
    
    • 函数执行结果:

    参考文献

    1. ECMAScript 6入门--第16章 Generator函数的语法
  • 相关阅读:
    mysql中文乱码的一点理解
    Linux 运行进程实时监控pidstat命令
    深入理解“系统平均负载”
    进程和线程的区别
    vmstat命令
    grep命令
    top命令
    Shell脚本获取本机ip
    CentOS7防火墙(firewall)配置
    大数据测试
  • 原文地址:https://www.cnblogs.com/omg-two/p/6875617.html
Copyright © 2020-2023  润新知