ECMAScript6 入门 Generator

----------------------------------------------------------------------------------------------------------------------------

基本概念
Generator 函数是一个状态机,封装了多个内部状态,执行 Generator 函数会返回一个遍历器对象
Generator 函数除了状态机,还是一个遍历器对象生成函数,
返回的遍历器对象,可以依次遍历 Generator 函数内部的每一个状态

function* helloWorldGenerator() {
  yield 'hello';
  yield 'world';
  return 'ending';
}

var hw = helloWorldGenerator();
该函数存在三个状态了

----------------------------------------------------------------------------------------------------------------------------

调用 Generator 函数后,该函数并不执行
返回的也不是函数运行结果,而是一个指向内部状态的指针对象(遍历器对象)

下一步,必须调用遍历器对象的next方法,使得指针移向下一个状态
返回的对象是yield表达式的值以及遍历是否完成
(遇到下一个yield或者return为止)
hw.next()
// { value: 'hello', done: false }

hw.next()
// { value: 'world', done: false }

hw.next()
// { value: 'ending', done: true }

hw.next()
// { value: undefined, done: true }

----------------------------------------------------------------------------------------------------------------------------

yield 表达式
遍历器对象的next方法的运行逻辑如下
(1)遇到yield表达式,就暂停执行后面的操作,并将紧跟在yield后面的那个表达式的值,作为返回的对象的value属性值。
(2)下一次调用next方法时,再继续往下执行,直到遇到下一个yield表达式。
(3)如果没有再遇到新的yield表达式,就一直运行到函数结束,直到return语句为止,
并将return语句后面的表达式的值,作为返回的对象的value属性值。
(4)如果该函数没有return语句,则返回的对象的value属性值为undefined。
注意:yield表达式后面的表达式,只有当调用next方法、内部指针指向该语句时才会执行(如果没有执行到这一步,就永远都不会执行该表达式)
(因此相等于手动提供了一个“惰性求值”的语法功能)
(5)yield不能进行嵌套操作,并且yield必须在定义的function*()函数里面,在数组等其他的回调函数是不起作用
//(6) yiled 后面使用的返回必须是返回了一个Promise对象

重点:bluebirdjs 类库会将普通函数转化成返回Promise对象的函数

----------------------------------------------------------------------------------------------------------------------------
next() 方法的参数
1:该参数会被当成上一个yield表达式的返回值
----------------------------------------------------------------------------------------------------------------------------

for...of 循环
for...of循环可以自动遍历 Generator 函数时生成的Iterator对象,且此时不再需要调用next方法
1:一旦next方法的返回对象的done属性为true,for...of循环就会中止,且不包含该返回对象,就是不包含最后的那个return

----------------------------------------------------------------------------------------------------------------------------

Generator.prototype.throw()
Generator 函数返回的遍历器对象,都有一个throw方法,可以在函数体外抛出错误,然后在 Generator 函数体内捕获

----------------------------------------------------------------------------------------------------------------------------

Generator.prototype.return()
Generator 函数返回的遍历器对象,还有一个return方法,可以返回给定的值,并且终结遍历 Generator 函数
注释:return与next的简单区别
1:console.log(g.return('foo')); // { value: "foo", done: true } 终结了所以是true,并且返回了指定的值
2:return没有参数的时候,返回{ value: undefined, done: true }
3:next没有参数的时候返回本次yield语句的返回值
4:return有参数的时候,覆盖本次yield语句的返回值,也就是说,返回{ value: 参数, done: true };
next有参数的时候,覆盖上次yield语句的返回值

----------------------------------------------------------------------------------------------------------------------------

next()、throw()、return() 的共同点
next()、throw()、return()这三个方法本质上是同一件事,可以放在一起理解。它们的作用都是让 Generator 函数恢复执行,并且使用不同的语句替换yield表达式

----------------------------------------------------------------------------------------------------------------------------

yield* 表达式
如果在 Generator 函数内部,调用另一个 Generator 函数,默认情况下是没有效果的
单纯的使用另一个Generator无效
yield* fn() 这样才会起效果

----------------------------------------------------------------------------------------------------------------------------

作为对象属性的 Generator 函数

----------------------------------------------------------------------------------------------------------------------------

Generator 函数的this

----------------------------------------------------------------------------------------------------------------------------

Generator 与状态机
1:常用的状态机写法
var ticking = true;
var clock = function() {
  if (ticking)
    console.log('Tick!');
  else
    console.log('Tock!');
  ticking = !ticking;
}
上面代码的clock函数一共有两种状态(Tick和Tock),每运行一次,就改变一次状态:

2:Generator的写法
var clock = function*() {
  while (true) {
    console.log('Tick!');
    yield;
    console.log('Tock!');
    yield;
  }
};

----------------------------------------------------------------------------------------------------------------------------
Generator 函数的异步应用

已知的异步编程
{
    回调函数
    事件监听
    发布/订阅
    Promise对象
}

回调函数写法
fs.readFile('/etc/passwd', 'utf-8', function (err, data) {
  if (err) throw err;
  console.log(data);
});

Promise写法
var readFile = require('fs-readfile-promise');

readFile(fileA)
.then(function (data) {
  console.log(data.toString());
})
.then(function () {
  return readFile(fileB);
})
.then(function (data) {
  console.log(data.toString());
})
.catch(function (err) {
  console.log(err);
});

Generator写法
function* gen(x) {
  var y = yield x + 2;
  return y;
}

var g = gen(1);
g.next() // { value: 3, done: false }
g.next() // { value: undefined, done: true }

数据交换与错误解决
{
    next返回值的value属性,是Generator函数向外输出,next函数还可以接受参数向函数体输入数据
    Generator函数体内部还可以部署错误处理代码,捕获函数体外抛出的错误
    
}

参数的求值策略
{
    传值调用:在进入函数体之前进行调用
    传名调用:将表达式传入函数体,在执行的时候才调用
}

Thunk 函数替换的不是表达式,而是多参数函数,将其替换成一个只接受回调函数作为参数的单参数函数

Generator函数的自动执行方法
{
    
    
    
}
不忘初心,不负梦想
原文地址:https://www.cnblogs.com/panrui1994/p/11597685.html