[ES6] Generator(生成器)
#
生成器
function*
function* name([param[, param[, ... param]]]) { statements }
声明(function关键字后跟一个星号)定义一个generator(生成器)函数,返回一个Generator对象。
也可以用GeneratorFunction构造器和function* expression定义一个generator函数。
生成器是一种可以从中退出并在之后重新进入的函数。
生成器的环境(绑定的变量)会在每次执行后被保存,下次进入时可继续使用。
调用一个生成器函数并不马上执行它的主体,而是返回一个这个生成器函数的迭代器(iterator)对象。
当这个迭代器的next()方法被调用时,生成器函数的主体会被执行直至第一个yield表达式,该表达式定义了迭代器返回的值,或者,被 yield*委派至另一个生成器函数。
next()方法返回一个对象,该对象有一个value属性,表示产出的值,和一个done属性,表示生成器是否已经产出了它最后的值。
#
function* idMaker() {
var index = 0;
while (index < 3)
yield index++;
}
var gen = idMaker();
console.log(gen.next().value); // 0
console.log(gen.next().value); // 1
console.log(gen.next().value); // 2
console.log(gen.next().value); // undefined
#
function* anotherGenerator(i) {
yield i + 1;
yield i + 2;
yield i + 3;
}
function* generator(i) {
yield i;
yield * anotherGenerator(i);
yield i + 10;
}
var gen = generator(10);
console.log(gen.next().value); // 10
console.log(gen.next().value); // 11
console.log(gen.next().value); // 12
console.log(gen.next().value); // 13
console.log(gen.next().value); // 20
#yield命令是异步两个阶段的分界线。
协程遇到yield命令就暂停,等到执行权返回,再从暂停的地方继续往后执行。
function *asnycJob() { // ...其他代码 var f = yield readFile(fileA);//执行到此处,执行权将交给其他协程。 // ...其他代码 }
#
function* gen(x) { var y = yield x + 2; return y; } var g = gen(1); console.log(g.next()); // { value: 3, done: false } console.log( g.next(2)); // { value: 2, done: true }
#
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(); var result = g.next();//Fetch模块返回的是一个Promise对象 result.value.then(function(data){ return data.json(); }).then(function(data){ g.next(data); });
#
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(); var result = g.next();//Fetch模块返回的是一个Promise对象 result.value.then(function(data){ return data.json(); }).then(function(data){ g.next(data); });
Generator.prototype.next()
gen.next(value)
next() 方法返回一个包含属性 done 和 value 的对象.
该方法也可以通过接受一个参数用以向生成器传值.
#使用 next()方法
function* gen() { yield 1; yield 2; yield 3; } var g = gen(); // "Generator { }" console.log(g); // "Object { value: 1, done: false }" console.log(g.next()); // "Object { value: 2, done: false }" console.log(g.next()); // "Object { value: 3, done: false }" console.log(g.next()); // "Object { value: undefined, done: true }" console.log(g.next());
#调用 next 方法并传入了参数
function* gen() { while(true) { var value = yield null; //首次调用 next 方法时没有出任何输出, 这是因为初始状态时生成器通过yield 返回了null. console.log(value);//2 } } var g = gen(); // "Generator { }" console.log(g); // "Object {value: null, done: false}" console.log(g.next(1)); // "Object {value: null, done: false}" console.log(g.next(2));
Generator.prototype.return()
gen.return(value)
return() 方法返回给定的值并结束生成器.
#使用 return()方法
function* gen() { yield 1; yield 2; yield 3; } var g = gen(); // "Generator { }" console.log(g.next()); // { value: 1, done: false } console.log(g.return("foo")); // { value: "foo", done: true } console.log(g.next()); // { value: undefined, done: true }
Generator.prototype.throw()
gen.throw(exception)
throw() 方法用来向生成器抛出异常.
#使用 throw()
function* gen() { while (true) { try { yield 42; } catch (e) { console.log("Error caught!"); } } } var g = gen(); console.log(g.next()); // { value: 42, done: false } console.log(g.throw(new Error("Something went wrong"))); // "Error caught!" //Object {value: 42, done: false}
GeneratorFunction(生成器函数)
new GeneratorFunction ([arg1[, arg2[, ...argN]],] functionBody)
GeneratorFunction构造器生成新的generator function 对象。
在JavaScript中,生成器函数实际上都是GeneratorFunction的实例对象
#GeneratorFunction并不是一个全局对象。可以通过下面的代码获取。
Object.getPrototypeOf(function*(){}).constructor
#
var GeneratorFunction = Object.getPrototypeOf(function*(){}).constructor var g = new GeneratorFunction("a", "yield a * 2"); var iterator = g(10); console.log(iterator.next().value); // 20
function* expression (function*表达式)
function* [name]([param1[, param2[, ..., paramN]]]) {
statements
}
function*关键字可以在表达式内部定义一个生成器函数。
function*表达式和function* 声明比较相似,并具有几乎相同的语法。
function*表达式和function*声明之间主要区别就是函数名,即在创建匿名函数时,function*表达式可以省略函数名
#定义了一个未命名的生成器函数并把它赋值给x,函数产出(yield)它的传入参数的平方
var x = function*(y) { yield y * y; };