Generator 函数是 ES6 提供的一种异步编程解决方案
教程可查看 阮老师所著es6
用例1,对象转可执行的数组
var myIterable = {};
myIterable[Symbol.iterator] = function* () {
yield 1;
yield 2;
yield 3;
};
console.log([...myIterable]);
2. 向generator 内部传值 ((1)
function* foo(x) {
var y = 2 * (yield (x + 1));
var z = yield (y / 3);
return (x + y + z);
}
var a = foo(5);
a.next() // 6
a.next() //NaN
a.next() //NaN
var b = foo(5);
b.next() //6
b.next(12) //8
b.next(13) //42
向 generator 内部传值(2)
function* dataConsumer() {
console.log('Started');
console.log('start two');
console.log(`1. ${ yield }`);
console.log(`2. ${ yield }`);
return 'result';
}
let genObj = dataConsumer();
genObj.next();
//Started
genObj.next('a')
//1. a
genObj.next('b')
//2. b
3,第一次调用传参
function wrapper(generatorFunction) {
return function (...args) {
let generatorObject = generatorFunction(...args);
generatorObject.next()
return generatorObject;
};
}
const wrapped = wrapper(function* () {
console.log(`First input: ${yield}`);
return 'DONE';
});
wrapped().next('hello!')
4,对比用 generator 函数和普通函数 生成斐波那契数列
function* gennerator(){
let [ prev, curr ] = [ 0, 1 ];
for(;;){
yield curr;
[ prev,curr] = [curr,curr+prev];
}
}
for(let n of gennerator()){
if(n<1000){
console.log(n);
}
}
const fibonacci = (function(){
let cache = [];
return function(number){
if(typeof cache[number]!=="undefined"){
return cache[number]
}
return cache[number]=(number==1||number==0)?number:fibonacci(number-2)+fibonacci(number-1);
}
})()
console.log(fibonacci(100));
5,给对象部署iterator 接口
function* objectEntries() {
let propKeys = Object.keys(this);
for (let propKey of propKeys) {
yield [propKey, this[propKey]];
}
}
let jane = { first: 'Jane', last: 'Doe' };
jane[Symbol.iterator] = objectEntries;
for (let [key, value] of jane) {
console.log(`${key}: ${value}`);
}
6 ,Generator.prototype.throw()
Generator 函数返回的遍历器对象,都有一个throw方法,可以在函数体外抛出错误,然后在 Generator 函数体内捕获。
注:内部的catch 语句只能执行一次错误 第二次错误 会被外部的catch 语句捕获
var g = function* () {
try {
yield;
} catch (e) {
console.log('内部捕获', e);
}
};
var i = g();
i.next();
try {
i.throw('a');
i.throw('b');
} catch (e) {
console.log('外部捕获', e);
}
7. Generator.prototype.return()
Generator 函数返回的遍历器对象,还有一个return方法,可以返回给定的值,并且终结遍历 Generator 函数。
function* gen() {
yield 1;
yield 2;
yield 3;
}
let g = gen();
console.log(g.next()); //{value: 1, done: false}
console.log(g.return("response")); //{value: "response", done: true}
console.log(g.next()); //{value: undefined, done: true}
如果 Generator 函数内部有try...finally代码块,且正在执行try代码块,那么return方法会推迟到finally代码块执行完再执行。
function* numbers () {
yield 1;
try {
yield 2;
yield 3;
} finally {
yield 4;
yield 5;
}
yield 6;
}
var g = numbers();
g.next() // { value: 1, done: false }
g.next() // { value: 2, done: false }
g.return(7) // { value: 4, done: false }
g.next() // { value: 5, done: false }
g.next() // { value: 7, done: true }
8, yield* 表达式
如果在 Generator 函数内部,调用另一个 Generator 函数,默认情况下是没有效果的。
function* foo(){
yield 'a';
yield 'b';
}
function* bar(){
yield "x";
foo();
yield "y";
}
for (let v of bar()){
console.log(v);
}
这个就需要用到yield*
表达式,用来在一个 Generator 函数里面执行另一个 Generator 函数。
function* bar() {
yield 'x';
yield* foo();
yield 'y';
}
// 等同于
function* bar() {
yield 'x';
yield 'a';
yield 'b';
yield 'y';
}
// 等同于
function* bar() {
yield 'x';
for (let v of foo()) {
yield v;
}
yield 'y';
}
for (let v of bar()){
console.log(v);
}
// "x"
// "a"
// "b"
// "y"
如果yield*
后面跟着一个数组,由于数组原生支持遍历器,因此就会遍历数组成员。
function* gen(){
yield* ["a", "b", "c"];
}
gen().next() // { value:"a", done:false }
实际上,任何数据结构只要有 Iterator 接口,就可以被yield*
遍历。
let read = (function* () {
yield 'hello';
yield* 'hello';
})();
read.next().value // "hello"
read.next().value // "h"
yield*
命令可以很方便地取出嵌套数组的所有成员。
function* iterTree(tree) {
if (Array.isArray(tree)) {
for(let i=0; i < tree.length; i++) {
yield* iterTree(tree[i]);
}
} else {
yield tree;
}
}
const tree = [ 'a', ['b', 'c'], ['d', 'e'] ];
for(let x of iterTree(tree)) {
console.log(x);
}
// a