Generator函数

1.Generator函数是ES6增加的异步编程解决方案之一,与普通的函数行为完全不同,类似于一个状态机,内部封装了多个状态。

在函数定义的形式上,跟普通函数差不多,有两处不同,一是function关键字与函数名之间需要一个星号(*),二是函数内部使用yield语句定义各种状态,且yield只能用在Generator函数中,否则报错,如下所示

function* testGenerator(){//星号只要在function与函数名之间就可
yield 'test';
yield 'generator';
return '!';
} function testYield(){
yield 'hello';//报错,但在ff浏览器中不会报错,被自动认为是Generator函数
}
VM1211:9 Uncaught SyntaxError: Unexpected string(…)

调用Generator函数,该函数不会立即执行,而是返回一个遍历器Iterator,必须调用该遍历器的next方法去遍历函数内部的下一个状态,如下所示

function* generator(){
console.log('hehe');
yield 'hello';
yield 'ecmascript';
return 'end';
}
var gen = generator();
gen.next();
hehe
Object { value: "hello", done: false }
gen.next()
Object { value: "ecmascript", done: false }
gen.next()
Object { value: "end", done: true }
gen.next()
Object { value: undefined, done: true }

当然也可以使用for..of或者扩展运算符遍历,但不会遍历到return返回值,如下所示

for(let x of generator()){
console.log(x);
}
hehe
hello
ecmascript
[...generator()].forEach((val,idx,arr)=>console.log(val));
hehe
hello
ecmascript

Generator函数中yield语句是暂停标志,可以不存在该语句,这时函数可以当作是暂缓执行函数,如下所示

function* genfunc(){
console.log("稍后执行...");
} var g = genfunc(); setTimeout(() => g.next(),2000);
3
稍后执行...

由于yield语句只能用在Generator函数中,因此在使用回调函数时需要特别的注意,比如在Generator函数使用数组的map,forEach方法时,不能在函数参数里面写yield语句,如下所示

function* arrGene(arr){
arr.forEach(function(val,idx,arr){
yield val;
});
}
console.log([...arrGene([1,2,3])]);
VM142:4 Uncaught SyntaxError: Unexpected identifier(…)
-------------------------使用for循环代替--------------------------
function* arrGene(arr){
for(let i=0,len=arr.length; i<len; i++){
yield arr[i];
}
}
console.log([...arrGene([1,2,3])]);
VM179:8 [1, 2, 3]

Generator是一个遍历器生成器,因此可以赋值给没有默认遍历器的对象的Symbol.iterator属性,让该对象能够使用for...of语句,如下所示

var obj = {};
obj[Symbol.iterator] = function* (){
yield 'hello';
yield 'world';
return '!';
}
for(let x of obj){
console.log(x);
}
hello
world

2.next方法参数

Generator实例的next方法可以传递参数,作为该实例内部上一个yield语句的返回值,如不通过next方法传值,yield语句的返回值总是undefined,如下所示

//不传值的情况
function* generator(){
console.log('hello generator...');
let v = yield 'ni';
let u = yield v+'test';
return u+v+'';
}
var f = generator()
f.next()
hello generator...
Object { value: "ni", done: false }
f.next()
Object { value: "undefinedtest", done: false }
f.next()
Object { value: "NaN", done: true }
//传值的情况
var z = generator();
z.next();
hello generator...
Object { value: "ni", done: false }
z.next('frist');
Object { value: "fristtest", done: false }
z.next('second');
Object { value: "secondfrist", done: true }

因此我们利用这一特性来向generator函数内部注入值来控制函数的执行,如下所示

unction* gene(){
console.log('start generating...');
let ret = yield 'hello';
if(ret == 'a'){
yield 'a';
}else{
yield 'b';
}
return 'ending';
}
var g = gene();
g.next()
start generating...
Object { value: "hello", done: false }
g.next('c');
Object { value: "b", done: false }
g.next();
Object { value: "ending", done: true }

3.Generator实例方法throw

throw方法可以在函数体外抛出错误,然后在generator函数内部捕获错误,但同时只能一条错误异常,如下所示

function* catchGene(){
try{
yield 'try';
}catch(e){
console.log('generator函数内部捕获:'+e);
}
}
var g = catchGene();
try{
console.log(g.next());
g.throw('a');
g.throw('b');
}catch(e){
console.log('全局捕获:'+e);
}
Object { value: "try", done: false }
generator函数内部捕获:a
全局捕获:b

如果在generator函数体内没有部署try...catch语句,则generator实例throw抛出的错误不能被捕获,可以被全局catch捕获,如下所示

function* gen(){
yield 'hello';
yield 'world';
}
var g = gen();
try{
g.throw('a');
}catch(e){
console.log('全局捕获:'+e);
}
全局捕获:a

不管是generator实例throw方法或者throw命令抛出的错误,只要被捕获了就不会影响generator函数的next方法的执行,否则遍历直接终止,如下所示

function* gen(){
yield 'hello';
yield 'world';
}
var g = gen();
console.log(g.next());
g.throw();
console.log(g.next());
VM226:7 Object {value: "hello", done: false}
VM226:8 Uncaught undefined
-----------------------使用try...catch捕获-----------------
function* gen(){
try{
yield 'hello'; }catch(e){
console.log(e);
}
yield 'world';
yield 'ending';
}
var g = gen();
console.log(g.next());
console.log(g.throw('a'));
console.log(g.next());
Object { value: "hello", done: false }
a
Object { value: "world", done: false }
Object { value: "ending", done: false }

特别注意的是catch捕获到错误后,继续执行到下一个yield语句,相当于再执行了一个next方法。

generator函数内部抛出的错误,可以被函数体外的catch捕获,这时由于报错,JS引擎认为generator函数遍历完毕,之后再调用next都是返回{value:undefined,done:true}对象,如下所示

function* gen(){
yield 'hello';
yield x+y;
yield 'world';
}
var g = gen();
console.log(g.next());
try{
console.log(g.next());
}catch(e){
console.log(e);
}
console.log(g.next());
Object { value: "hello", done: false }
ReferenceError: x is not defined
堆栈跟踪:
gen@debugger eval code:3:2
@debugger eval code:9:14 Object { value: undefined, done: true }

4.Generator实例方法return

该方法会返回给定的值,并终止generator函数的遍历,如下所示

function* gen(){
yield 'hello';
yield 'world';
}
var g = gen();
g.next()
Object { value: "hello", done: false }
g.return("return");
Object { value: "return", done: true }
g.next()
Object { value: undefined, done: true }

如果return方法没有给出任何值,则返回undefined,如果generator函数体内部部署了try...finally语句,return语句会被推迟到finally执行完后执行,如下所示

function* gen(){
try{
yield 'hello';
}finally{
yield 'world';
}
}
var g = gen();
g.next()
Object { value: "hello", done: false }
g.return("nihao")
Object { value: "world", done: false }
g.next()
Object { value: "nihao", done: true }
g.next()
Object { value: undefined, done: true }

5.yield*语句

yield*语句用在generator函数内部执行另一个遍历器对象,如下所示

function* letter(){
yield 'b';
yield 'c';
yield 'd';
}
function* gen(){
yield "a";
letter(); //直接调用没有效果
yield "e";
}
[...gen()]
Array [ "a", "e" ]
------------------------------------------
function* letter(){
yield 'b';
yield 'c';
yield 'd';
}
function* gen(){
yield "a";
yield* letter();//yield* 语句
yield "e";
}
[...gen()]
Array [ "a", "b", "c", "d", "e" ]

只要实现了Iterator接口的对象都可以使用yield*遍历,如下所示

function* gen(){
yield 1;
yield 2;
yield* [3,4,5,6,7];
yield 10;
}
console.log([...gen()]);
Array [ 1, 2, 3, 4, 5, 6, 7, 10 ]
----------------------------遍历嵌套函数-----------------------
function* walkArr(arr){
if(Array.isArray(arr)){
for(let v of arr){
yield* walkArr(v);
}
}else{
yield arr;
}
}
var w = walkArr([1,[2,[3,10,[9]]]]);
[...w];
Array [ 1, 2, 3, 10, 9 ]

Generator函数就介绍到此咯

ES6 - Note7:Generator函数的更多相关文章

  1. ES6的generator函数

    generator是什么? generator是ES6提供的一种异步编程解决方案,在语法上,可以把它理解为一个状态机,内部封装了多种状态.执行generator,会生成返回一个遍历器对象.返回的遍历器 ...

  2. ES6 学习 -- Generator函数

    (1)语法说明:Generator函数其实是一个普通函数,其有两个特点,一是,function关键字与函数名之间有一个星号(*):二是Generator函数内部使用yield表达式,定义不同的状态,然 ...

  3. 【es6】Generator 函数

    1. 基本概念 状态机,封装了多个内部状态 2. 应用 返回一个遍历器对象. 3. 代码形式 function* helloWorldGenertor() { yield 'hello'; yield ...

  4. ES6入门之Generator函数

    Generator Generator函数是ES6提供的一种异步编程解决方案,Generator函数是一个状态机,封装了多个内部状态. 执行Generator函数会返回一个遍历器对象,也就是说,Gen ...

  5. 转: ES6异步编程:Generator 函数的含义与用法

    转: ES6异步编程:Generator 函数的含义与用法 异步编程对 JavaScript 语言太重要.JavaScript 只有一根线程,如果没有异步编程,根本没法用,非卡死不可. 以前,异步编程 ...

  6. es6 generator函数

    es6 新增了Generator函数,一种异步编程的解决方案 回顾一下,es6 提供了新的遍历方法,for of ,适用于各种数据集合,统一了遍历操作,原生支持for of 集合的数据集合有.数组,字 ...

  7. ES6必知必会 (七)—— Generator 函数

    Generator 函数 1.Generator 函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同,通常有两个特征: function关键字与函数名之间有一个星号: 函数体内部使 ...

  8. ES6的新特性(17)——Generator 函数的异步应用

    Generator 函数的异步应用 异步编程对 JavaScript 语言太重要.Javascript 语言的执行环境是“单线程”的,如果没有异步编程,根本没法用,非卡死不可.本章主要介绍 Gener ...

  9. ES6的新特性(16)——Generator 函数的语法

    Generator 函数的语法 简介 基本概念 Generator 函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同.本章详细介绍 Generator 函数的语法和 API,它的 ...

随机推荐

  1. CentOS随笔 不断添加

    一.设置IP (1)临时IP  ifconfig eth0 192.168.120.16 (2)永久IP  vi /etc/sysconfig/network-scripts/ifcfg-eth0   ...

  2. 搭建ssh后的简化

    对于SSh框架的简化,我们可以从下面几个方面来剖析: 1.实体类entity 2.注入 3.类注解 下面,我来一一为大家讲解.ps:写的不好还请多多指教,欢迎大家"来找茬". 关于 ...

  3. 【PostgreSQL】PostgreSQL的安装

    到了新公司,新公司的数据库是使用PostgreSQL,第一次学习,第一次安装. 开始安装:

  4. Codeforces Round #361 (Div. 2) C

    C - Mike and Chocolate Thieves Description Bad news came to Mike's village, some thieves stole a bun ...

  5. (原).NET程序加入多语言包解决方案工具,超级棒

    Multi-Language Add-In Version 5.04.0088 for Visual Studio 2013 安装包:http://www.jollans.com/SetupMulti ...

  6. Xamarin的不归路-ios模拟器调整窗口大小

    ios模拟器调整窗口大小:

  7. HDU2433 BFS最短路

    Travel Time Limit: 10000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Sub ...

  8. DataTable转List(备忘)

    public static List ToList(DataTable dt) { List<Dictionary<string, object>> list = new Li ...

  9. 10000 Reasons(Matt Redman)

     这是一首很感动的主内歌曲,听了无首次,还是很感动,这里把歌词贴出来,一方面是为了记忆歌词,另一方面是为以后怀念记忆.(20:44:38) Bless the lord,oh my soul oh m ...

  10. Union-Find 检测无向图有无环路算法

    不相交集合数据结构(Disjoint-set data structure)是一种用于跟踪集合被分割成多个不相交的子集合的数据结构,每个集合通过一个代表来标识,代表即集合中的某个成员. Union-F ...