12 Generator_01

76 阅读4分钟
├── Generator
│   ├── 简介
│   │     └─ 基本概念
│   │         └─ Generator 函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同
│   │         └─ 执行 Generator 函数会返回一个遍历器对象,也就是说,Generator 函数除了状态机,还是一个遍历器对象生成函数。
│   │         └─ Generator 函数的调用方法与普通函数一样,也是在函数名后面加上一对圆括号。不同的是必须调用遍历器对象的 `next`方法,使得指针移向下一个状态。
│   │         └─ function * foo(x, y) { ··· } function *foo(x, y) { ··· } function* foo(x, y) { ··· } function*foo(x, y) { ··· } 写法均可
│   │     └─ yield 表达式
│   │         └─ `yield`表达式与`return`语句既有相似之处,也有区别。相似之处在于,都能返回紧跟在语句后面的那个表达式的值。区别在于每次遇到`yield`,函数暂停执行,下一次再从该位置继续向后执行,而`return`语句不具备位置记忆的功能。
│   │         └─ 正常函数只能返回一个值,因为只能执行一次`return`Generator 函数可以返回一系列的值,因为可以有任意多个`yield`。
│   │         └─ 一个函数里面,只能执行一次(或者说一个)`return`语句,但是可以执行多次(或者说多个)`yield`表达式。
│   ├── for...of 循环
│   │     └─ `for...of`循环可以自动遍历 Generator 函数运行时生成的`Iterator`对象,且此时不再需要调用`next`方法。
│   │     └─ 除了`for...of`循环以外,扩展运算符(`...`)、解构赋值和`Array.from`方法内部调用的,都是遍历器接口。这意味着,它们都可以将 Generator 函数返回的 Iterator 对象,作为参
│   ├── Generator.prototype.throw()
│   │     └─ Generator 函数返回的遍历器对象,都有一个`throw`方法,可以在函数体外抛出错误,然后在 Generator 函数体内捕获。
│   │     └─ 遍历器对象`i`连续抛出两个错误。第一个错误被 Generator 函数体内的`catch`语句捕获。`i`第二次抛出错误,由于 Generator 函数内部的`catch`语句已经执行过了,不会再捕捉到这个错误了,所以这个错误就被抛出了 Generator 函数体,被函数体外的`catch`语句捕获。
│   │     └─ `throw`方法可以接受一个参数,该参数会被`catch`语句接收,建议抛出`Error`对象的实例。
│   │     └─ `throw`命令与`g.throw`方法是无关的,两者互不影响。 不要混淆遍历器对象的`throw`方法和全局的`throw`命令
│   │     └─ 如果 Generator 函数内部没有部署`try...catch`代码块,那么`throw`方法抛出的错误,将被外部`try...catch`代码块捕获。
│   │     └─ `throw`方法抛出的错误要被内部捕获,前提是必须至少执行过一次`next`方法。
│   │     └─ `throw`方法被捕获以后,自动执行了一次`next`方法
│   ├── Generator.prototype.return()
│   │     └─ Generator 函数返回的遍历器对象还有一个`return()`方法,可以返回给定的值,并且终结遍历 Generator 函数。
│   │     └─ Generator 函数返回的遍历器对象`g`调用`return()`方法后,返回值的`value`属性就是`return()`方法的参数`foo`. 并且,Generator 函数的遍历就终止了,返回值的`done`属性为`true`,以后再调用`next()`方法,`done`属性总是返回`true`。如果`return()`方法调用时,不提供参数,则返回值的`value`属性为`undefined`。
│   │     └─ Generator 函数内部有`try...finally`代码块,且正在执行`try`代码块,那么`return()`方法会导致立刻进入`finally`代码块,执行完以后,整个函数才会结束。
│   ├── next()、throw()、return() 的共同点
│   │     └─ 它们的作用都是让 Generator 函数恢复执行,并且使用不同的语句替换`yield`表达式。
│   │     └─ `next()`是将`yield`表达式替换成一个值。
│   │     └─ `throw()`是将`yield`表达式替换成一个`throw`语句。
│   │     └─ `return()`是将`yield`表达式替换成一个`return`语句。
│   ├── yield* 表达式
│   │     └─ ES6 提供了`yield*`表达式,作为解决办法,用来在一个 Generator 函数里面执行另一个 Generator 函数。
│   │     └─ 如果`yield`表达式后面跟的是一个遍历器对象,需要在`yield`表达式后面加上星号,表明它返回的是一个遍历器对象。这被称为`yield*`表达式。
│   │     └─ 如果`yield*`后面跟着一个数组,由于数组原生支持遍历器,因此就会遍历数组成员。`yield`命令后面如果不加星号,返回的是整个数组,加了星号就表示返回的是数组的遍历器对象。
│   ├── 作为对象属性的 Generator 函数
│   │     └─ 如果一个对象的属性是 Generator 函数,可以简写成下面的形式。let obj = { * myGeneratorMethod() { ··· } };
│   │     └─ 等同于 let obj = { myGeneratorMethod: function* () { // ··· };