ES6 - Note7:Generator函数
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函数的更多相关文章
- ES6的generator函数
generator是什么? generator是ES6提供的一种异步编程解决方案,在语法上,可以把它理解为一个状态机,内部封装了多种状态.执行generator,会生成返回一个遍历器对象.返回的遍历器 ...
- ES6 学习 -- Generator函数
(1)语法说明:Generator函数其实是一个普通函数,其有两个特点,一是,function关键字与函数名之间有一个星号(*):二是Generator函数内部使用yield表达式,定义不同的状态,然 ...
- 【es6】Generator 函数
1. 基本概念 状态机,封装了多个内部状态 2. 应用 返回一个遍历器对象. 3. 代码形式 function* helloWorldGenertor() { yield 'hello'; yield ...
- ES6入门之Generator函数
Generator Generator函数是ES6提供的一种异步编程解决方案,Generator函数是一个状态机,封装了多个内部状态. 执行Generator函数会返回一个遍历器对象,也就是说,Gen ...
- 转: ES6异步编程:Generator 函数的含义与用法
转: ES6异步编程:Generator 函数的含义与用法 异步编程对 JavaScript 语言太重要.JavaScript 只有一根线程,如果没有异步编程,根本没法用,非卡死不可. 以前,异步编程 ...
- es6 generator函数
es6 新增了Generator函数,一种异步编程的解决方案 回顾一下,es6 提供了新的遍历方法,for of ,适用于各种数据集合,统一了遍历操作,原生支持for of 集合的数据集合有.数组,字 ...
- ES6必知必会 (七)—— Generator 函数
Generator 函数 1.Generator 函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同,通常有两个特征: function关键字与函数名之间有一个星号: 函数体内部使 ...
- ES6的新特性(17)——Generator 函数的异步应用
Generator 函数的异步应用 异步编程对 JavaScript 语言太重要.Javascript 语言的执行环境是“单线程”的,如果没有异步编程,根本没法用,非卡死不可.本章主要介绍 Gener ...
- ES6的新特性(16)——Generator 函数的语法
Generator 函数的语法 简介 基本概念 Generator 函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同.本章详细介绍 Generator 函数的语法和 API,它的 ...
随机推荐
- CentOS随笔 不断添加
一.设置IP (1)临时IP ifconfig eth0 192.168.120.16 (2)永久IP vi /etc/sysconfig/network-scripts/ifcfg-eth0 ...
- 搭建ssh后的简化
对于SSh框架的简化,我们可以从下面几个方面来剖析: 1.实体类entity 2.注入 3.类注解 下面,我来一一为大家讲解.ps:写的不好还请多多指教,欢迎大家"来找茬". 关于 ...
- 【PostgreSQL】PostgreSQL的安装
到了新公司,新公司的数据库是使用PostgreSQL,第一次学习,第一次安装. 开始安装:
- Codeforces Round #361 (Div. 2) C
C - Mike and Chocolate Thieves Description Bad news came to Mike's village, some thieves stole a bun ...
- (原).NET程序加入多语言包解决方案工具,超级棒
Multi-Language Add-In Version 5.04.0088 for Visual Studio 2013 安装包:http://www.jollans.com/SetupMulti ...
- Xamarin的不归路-ios模拟器调整窗口大小
ios模拟器调整窗口大小:
- HDU2433 BFS最短路
Travel Time Limit: 10000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Sub ...
- DataTable转List(备忘)
public static List ToList(DataTable dt) { List<Dictionary<string, object>> list = new Li ...
- 10000 Reasons(Matt Redman)
这是一首很感动的主内歌曲,听了无首次,还是很感动,这里把歌词贴出来,一方面是为了记忆歌词,另一方面是为以后怀念记忆.(20:44:38) Bless the lord,oh my soul oh m ...
- Union-Find 检测无向图有无环路算法
不相交集合数据结构(Disjoint-set data structure)是一种用于跟踪集合被分割成多个不相交的子集合的数据结构,每个集合通过一个代表来标识,代表即集合中的某个成员. Union-F ...