对ES6Generator函数的理解

什么是Generator函数

Generator 函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同。

  简单说Generator函数是ES6新推出的一种语法,其目的是为了给JS的异步式编程提供一种更好的解决方案.在传统的回调函数异步式编程中,存在的一个最大的问题就是,如果要进行大量的异步式操作时,那么其代码将会一个嵌套者一个.这样一旦嵌套过多,将会造成代码难以理解.并且其代码之间高度耦合.

1
2
3
4
5
6
7
8
9
$.get("./data1.json",function(data1){
console.log(data1)
$.get("./data2.json",function(data2){
console.log(data2)
$.get("./data3.json",function(data3){
console.log(data3);
})
})
})

Generator函数的基本概念

  Generator 函数有多种理解角度。从语法上,首先可以把它理解成,Generator 函数是一个状态机,封装了多个内部状态。
  执行 Generator 函数会返回一个遍历器对象,也就是说,Generator 函数除了状态机,还是一个遍历器对象生成函数。返回的遍历器对象,可以依次遍历 Generator 函数内部的每一个状态。
  形式上,Generator 函数是一个普通函数,但是有两个特征。一是,function关键字与函数名之间有一个星号;二是,函数体内部使用yield表达式,定义不同的内部状态(yield在英语里的意思就是“产出”)。
Generator 函数是协程在 ES6 的实现,最大特点就是可以交出函数的执行权(即暂停执行)。

上面是阮一峰所写的ECMAScript 6 入门中对于Generator函数概念的描述.

  对此我的理解是Generator函数在形式上没有什么区别.只是在定义的时候需要在

```*```符号.其次,在执行的时候,Generator函数内部如果没有```yield```关键字时,那就一个有着依次暂停的普通函数.
1
2
3
4
5
6
7
8
9
10
11
```JavaScript
function * fn(str) {
console.log(str);
}
let f = fn("aaaa");
console.log(f) //{[[GeneratorStatus]]: "suspended"}
f.next(); // aaaa

  从是上代码中可以看到,代码中首先定义了一个Generator函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
并将函数的返回值传给变量```f```.再打印```f```.最后用```f```调用```nex()```方法.
  而在执行了上述代码后可以看到.函数在第一次调用时并没有执行内部的代码,而是返回了一个对象,在使用这个对象调用了```next```方法之后才真正的执行了函数内部的代码.这就是普通的Generator函数在内部没有```yield```关键字时的执行过程.除了有一次暂停外,就结果而言,它与普通函数并没有什么不同.
  
  但是当```Generator```函数中使用了```yield```关键字后.代码的执行就有了改变.
```JavaScript
function * fn() {
console.log("a");
let a = "abc";
yield a;
console.log("b");
let b = "123";
yield b;
let c = "张三"
return c;
}
let f = fn();
console.log(f.next()) // a
// {value: "abc", done: false}
console.log(f.next()) // b
// {value: "123", done: false}
console.log(f.next())
// {value: undefined, done: true}
console.log(f.next())
// {value: undefined, done: true}

  在上面的代码中,我们定义了一个Generator函数,并在函数的内部定义了两个yield关键字,然后执行这个函数,并在相应的地方打印出值.在打印的结果中可以看出.yield关键字在函数运行中会将函数暂停.这个时候只有再次调用next()方法才能继续执行Generator函数.同时yield还将会返回一个对象,这个对象中包含两个属性.一个是value,一个是done.其中value值是对应的yield关键字后面所跟的值.而done则表示所属的Generator函数后面是否还有需要执行的代码.

  上面是我个人对Generator函数的运行机制的一个理解,说的可能有点乱.没有表述清楚.所以我在呢下面引用了阮一峰ECMAScript 6 入门中对Generator函数的描述.希望对大家有所帮助

总结一下,调用 Generator 函数,返回一个遍历器对象,代表 Generator 函数的内部指针。以后,每次调用遍历器对象的next方法,就会返回一个有着value和done两个属性的对象。value属性表示当前的内部状态的值,是yield表达式后面那个表达式的值;done属性是一个布尔值,表示是否遍历结束。

  由于 Generator 函数返回的遍历器对象,只有调用next方法才会遍历下一个内部状态,所以其实提供了一种可以暂停执行的函数。yield表达式就是暂停标志。
遍历器对象的next方法的运行逻辑如下。
(1)遇到yield表达式,就暂停执行后面的操作,并将紧跟在yield后面的那个表达式的值,作为返回的对象的value属性值。
(2)下一次调用next方法时,再继续往下执行,直到遇到下一个yield表达式。
(3)如果没有再遇到新的yield表达式,就一直运行到函数结束,直到return语句为止,并将return语句后面的表达式的值,作为返回的对象的value属性值。
(4)如果该函数没有return语句,则返回的对象的value属性值为undefined。
  需要注意的是,yield表达式后面的表达式,只有当调用next方法、内部指针指向该语句时才会执行,因此等于为 JavaScript 提供了手动的“惰性求值”(Lazy Evaluation)的语法功能。

浏览器兼容性

PC端:

这里写图片描述

移动端:
这里写图片描述

参考文档:阮一峰 - ECMAScript 6 入门