ES6 之生成器


作者:Seiya

时间:2019年08月26日


生成器


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

    语法上,首先可以把它理解成,Generator 函数是一个状态机,封装了多个内部状态。


  • Generator 函数除了状态机,还是一个遍历器对象生成函数

    可暂停函数(惰性求值), yield 可暂停,next 方法可启动。每次返回的是 yield 后的表达式结果




特点

  • function关键字与函数名之间有一个星号;

  • 函数体内部使用yield表达式,定义不同的内部状态:


举个例子:

function* generatorExample(){
  yield 'hello';
  yield 'generator';
}

我们可以这样使用:

let MG = generatorExample() // 返回指针对象
MG.next() // {value: "hello", done: false}
MG.next() // {value: "generator", done: false}
MG.next() // {value: "undefined", done: true}

第一次调用,Generator 函数开始执行,直到遇到第一个 yield 表达式为止。next 方法返回一个对象,它的 value 属性就是当前 yield 表达式的值 hello,done 属性的值 false ,表示遍历还没有结束。

第二次调用,Generator 函数从上次yield表达式停下的地方,一直执行到下一个 yield 表达式。next 方法返回的对象的 value 属性就是当前 yield 表达式的值 world,done 属性的值 false,表示遍历还没有结束。

第三次调用,由于没有 return 语句,此时 Generator 函数已经运行完毕,next 方法返回对象的 value 属性为 undefined,done 属性为 true。以后再调用 next 方法,返回的都是这个值。




next传递参数

yield 表达式本身没有返回值,或者说总是返回 undefined。next 方法可以带一个参数,该参数就会被当作上一个 yield 表达式的返回值。


我们来看一个例子:

function* generatorExample () {
  let result = yield 'hello'
  console.log(result)
  yield 'generator'
}

运行结果如下:

let MG = generatorExample()
MG.next() // {value: "hello", done: false}
MG.next(11) // 11 {value: "generator", done: false}
MG.next() // {value: "undefined", done: true}



与 Iterator 接口的关系

在《ES6 之迭代器》疑问中提到对象没有 iterator 接口,用 for...of 遍历时便会报错。

由于 Generator 函数就是遍历器生成函数,因此可以把 Generator 赋值给对象的 Symbol.iterator 属性,从而使得该对象具有 Iterator 接口。

let obj = { username: 'kobe', age: 39 }
obj[Symbol.iterator] = function* myTest() {
  yield 1;
  yield 2;
  yield 3;
};
for (let i of obj) {
  console.log(i) // 1 2 3
}



Generator的异步的应用

var fetch = require('node-fetch');

function* gen(){
  var url = 'https://api.github.com/users/github';
  var result = yield fetch(url);
  console.log(result.bio);
}

我们可以这样使用:

var g = gen();  // 获取遍历器对象

/**
 * 使用 next 方法,执行异步任务的第一阶段,即 fetch(url)
 * 注意:fetch(url) 会返回一个 Promise 对象,所以 result 的值为:{ value: Promise { <pending> }, done: false }
 */
var result = g.next();

result.value.then(function(data){
  return data.json();
}).then(function(data){
  g.next(data);   // 调用 g.next,将获得的数据传进去
});
最后更新时间: 2019-8-26 16:26:34