1. 语法和API

一种异步编程解决方案。
  执行Generator函数返回一个遍历器对象;里面封装了多个状态;可遍历内部的每一个状态。
格式:
1.function 与函数名之间加“*”号。
2.函数内部使用yield语句定义不同的内部状态。

示例:

//yeild语句暂停执行、return函数执行结束
function* test(){
     yield 'hello';
     yield 'world';
     return  'ending';
}

 函数只能执行一次return语句,所以return后函数执行结束。
 和普通函数调用方式相同,实例对象调用next()方法获取yield语句后的值。yield语句不能用于普通函数

    var t = test();
    //返回一个对象,包含两个值{value:"",done:""}
    t.next();  //{value:"hello",done:false}
    t.next();  //{value:"world",done:false}
    t.next();  //{value:"ending",done:true}
    t.next();  //{value:undefined,done:true}

使用next()可阶段性获取到函数中yield语句后的值,可根据done的值为true确认函数是否执行完毕。

1.yield语句在表达式中时,须放在括号里。
2.用作函数参数或赋值表达式的右边,可以不加括号。

1.表达式
//需要将表达式中获取的值在下一次执行next()传递进去。不然console输出undefined
function* test(){
         yield 'hello';
  console.log((yield "ds"));
         yield 'world';
         return  'ending';
    }
var t = test();
t.next();
var p = t.next();
t.next(p);
2.函数参数yield语句、赋值表达式的右边
let temp = yield "ii";

任意一个对象的Symbol.iterator方法等于该对象的遍历器对象生成函数。
yield语句没有返回值。

function* test(){
    //some code
}
var t = test();
t[Symbol.iterator]() === t

next()方法可传入参数
 yield语句不会返回值,总是undefined,则在使用yield语句在赋值表达式的右边时,需要在next()方法传入值。
 1.一般的Generator函数第一次使用next()方法不能带有参数,
 2.若需要第一次传参,则将Generator函数作为另一个函数的返回值,

function warpper(fn){
    return function(...args){
        let p = fn(...args);
        p.next();              //{value:undefined,done:true}
        return p;
    }
}
var warpped = warpper(function* (){
    console.log(`first args:${yield}`);
    return 'DONE';
});
let p = warpped();
p.next('hello');        //{value:'DONE',done:true}
p.next();              //{value:undefined,done:true}

for… of循环可以遍历Generator函数,
 不需要调用next()方法,在done值为true时,循环结束

//斐波那契数列
function* fibonacci(){
    let [prev,curr] = [0,1];
    for(;;){
        [prev,curr] = [curr,prev+curr];
        yield curr;
    }
}
for(let n of fibonacci()){
    if(n>1000) break;
    console.log(n);
}
//通过Generator函数添加Iterator接口,使得某些无法遍历的数据结构可遍历
function* objectEntries(obj){
    let keys = Reflect.ownKeys(obj);
    for(let key of keys){
        yield [key,obj[key]];
    }
}
//1.
let p = {name:'小李',age:'23'};
for(let [key,value] of objectEntries(p)){
    console.log(`${key}:${value}`);
}
//2.通过的对象Symbol.iterator属性
p[Symbol.iterator] = objectEntries;
for(let [key,value] of p){
    console.log(`${key}:${value}`);
}

Generator函数的throw()方法,可以在函数体外抛出错误,然后在Generator函数体内捕获;和全局的throw命令不同,只能被函数体外的catch语句捕获。
 1.如果函数体外的catch语句捕获了错误,就不会继续执行后面的语句
 2.如果函数内部没有try{}catch(){},throw()方法抛出的错误会被外部的catch语句捕获,执行终止;但是throw命令抛出的错误则不会影响遍历器状态。
 3.一旦Generator函数执行过程中使用throw命令抛出错误,就不会执行下去,终止。
Generator函数的return()方法,可以返回给定的值,并终结Generator函数的遍历。
 1.如果Generator函数中有try…finally 代码块,那么return语句会在finally代码块执行完后再执行返回值。
yield* 语句,用来在Generator函数中执行另一个Generator函数。

function* inner(){
    yield 'hello';
}
function* outer(){
    yield 'open';
    inner();     //不会执行
    yield inner();   //返回inner()的遍历器
    yield* inner();  //返回inner()遍历后的值
    yield 'word';
}

 1.任何有Iterator接口,就可以使用yield*遍历。
 2.被调用的Generator函数中有return 语句时,像调用函数中返回值。
 3.Generator函数返回的时遍历器对象,而不是this对象,这样this.x = ‘hello’;不会生效;可使用bind()绑定一个空对象给Generator函数。

2.Generator函数推导

惰性求值

1.状态机
 每执行一次函数,改变一次状态,执行不同的处理。
2.协程
 可以使用Generator函数交换程序执行的控制权。

3.应用

1.异步操作的同步化表达
2.控制流管理,
3.在对象上部署Iterator接口
4.作为数据结构,可以对任意表达式提供类似数组的接口。

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐