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. 【转】Microsoft .NET Framework 3.5 sp1 安装速度慢,快速离线安装的方法

    1.到官网上下载3.5SP1的完整安装包.2.下载完成后,命令行下运行dotnetfx35.exe/x,解压到一个目录(如D:"),此时会生成一个D:"wcu目录3.进入解压目录下 ...

  2. js get browser vertion (js获取浏览器信息版本)

    1问题:js get browser vertion (js获取浏览器信息版本) 2解决方案 Copy this script into your JavaScript files. It works ...

  3. vue.js的基本操作

    1.{{message}}输出data数据中的message. 2.v-for="todo in todos"输出data数据中的dotos数组 3.v-on:click=&quo ...

  4. asp.net 基礎部分一

    过程: 客户端像服务器发送一个请求,iis服务器接收到请求的数据,并且将数据交给c#程序进行处理,并且对数据库进行操作,并且将处理到的结果响应给浏览器客户端 过程2:第一次浏览器请求,后端应该发一个表 ...

  5. js判断只能输入数字和只能输入

    JS判断只能是数字和小数点 1.文本框只能输入数字代码(小数点也不能输入) <input onkeyup="this.value=this.value.replace(/\D/g,'' ...

  6. 【二】jekyll 的使用

    本系列有五篇:分别是 [一]Ubuntu14.04+Jekyll+Github Pages搭建静态博客:主要是安装方面 [二]jekyll 的使用 :主要是jekyll的配置 [三]Markdown+ ...

  7. Hbuilder开发HTML5 APP之WebView

    WebView就是原生的WebView,HBuilder在其上封装了一层,便于Javascript的调用,结构如图: 也可以实现这样的结构: 注意:WebView的使用属性HTML5+规范,所以必须等 ...

  8. 测试MailUtils,作用是发邮件

    package cn.itcast.test; import java.io.IOException; import javax.mail.MessagingException; import jav ...

  9. 扩展Bootstrap Tooltip插件使其可交互

    最近在公司某项目开发中遇见一特殊需求,请笔者帮助,因此有了本文的插件.在前端开发中tooltip是一个极其常用的插件,它能更好向使用者展示更多的文档等帮助信息.它们通常都是一些静态文本信息.但同事他们 ...

  10. 在C#代码中应用Log4Net(三)Log4Net中配置文件的解释

    一个完整的配置文件的例子如下所示,这个是”在C#代码中应用Log4Net(二)”中使用的配置文件. <log4net> <!-- 错误日志类--> <logger nam ...