ES6的generator函数
generator是什么?
generator是ES6提供的一种异步编程解决方案,在语法上,可以把它理解为一个状态机,内部封装了多种状态。执行generator,会生成返回一个遍历器对象。返回的遍历器对象,可以依次遍历generator函数的每一个状态。同时ES6规定这个遍历器是Generator函数的实例,也继承了Genarator函数的prototype对象上的方法。
最简单的generator函数,其实它就是一个普通的函数,但是它有两个特征。第一就是function关键字与函数名之间有一个*号,其二就是函数体内使用yield表达式来遍历状态:
function* newGenerator(){
yield 'hello';
yield 'world';
return 'ending';
}
执行generator函数之后,该函数并不会立即执行,返回的也不是函数运行结果,而是一个指向内部状态的指针对象。通常使用遍历器对象的next方法。使得指针移向下一个状态。每一次调用next()方法,内部指针就从函数头部或上一次停下里的地方开始执行,直到遇到下一个yield表达式位置,由此可以看出,generator是分段执行的,yield表达式是暂停执行的标记,而next方法可以恢复执行。
generator中的yield表达式
yield表达式在generator中是作为一个暂停标志,当碰到yield时,函数暂停执行,等到下一次next()执行时,函数才从当前yield位置开始执行。并且,yield表达式只能用在Generator函数里边;同时,yield如果后边带一个,则就是相当于一个for...of的简写形式,如果yield后边不带,则返回的是generator的值。
function* gen() {
yield 'hello';
yield* 'hello';
}
let f = gen();
console.log(f.next().value);
console.log(f.next().value);
console.log(f.next().value);
console.log(f.next().value);
console.log(f.next().value);
上述例子中的后四个next()函数,就会顺序的返回h e l l
generator中的next函数
通过next函数,可以执行对应的yield表达式,且next()函数还可以带参数,该参数可以作为上一次yield表达式的返回值,因为yield本身是没有返回值的,如果next()中不带参数,则yield每次运行之后的返回值都是为undefined;
function* dataConsumer() {
console.log('Started');
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
上述函数中,第一次运行next(),运行到第一个next()函数截止,第二个next运行时,传入的参数为'a';则运行到第二个yield地方截止,然后第一个yield运行的返回值为'a',依次类推,则得到上述结果。
另外,通过for...of可以循环generator中的所有状态,并且不需要使用next()函数。除了for...of循环以外,扩展运算符(...),解构赋值和Array.form方法内部调用的,都是遍历器接口。
generator生成的对象,还有其他一些函数,比如throw()用来抛出错误,return()用来定义返回值并终止generator的状态。
以上的三个方法在本质上其实是一样的,他们就是让generator恢复执行,并且使用不同的语句来替代yield语句。
- next()是将yield表达式替换成一个值
- throw()是将yield表达式替换成一个throw语句
- return()是将yield表达式替换成一个return语句
Generator与协程
协程可以理解为“协作的线程”或者“协作的函数”。协程既可以是单线程实现,也可以用多线程实现,前者是一种特殊的子例程,后者是一种特殊的线程。
协程有点像函数,又有点像线程,它的运行流程大致如下。
- 第一步,协程A开始执行
- 第二部,协程A执行到一半,进入暂停,执行权转移到协程B
- 第三步,(过了一段时间)协程B交换执行权
- 最后,协程A恢复执行
协程适合用于多任务运行环境,它与普通的线程很相似,都有自己的执行上下文,可以分享全局量。他们的不同之处在于,同一时间可以有多个线程处于运行状态,但是运行的协程只能有一个,其他协程都是处于暂停状态。
由于JavaScript是单线程,只能保持一个调用栈,引入协程之后,每一个任务可以保持自己的调用栈,这样就可以再抛出错误的时候找到原始的调用栈,不至于像异步操作的回调函数那样,一旦出错,原始的调用栈早就结束了。
Generator 函数是 ES6 对协程的实现,但属于不完全实现。Generator函数被称为“半协程”(semi-coroutine),意思是只有 Generator 函数的调用者,才能将程序的执行权还给 Generator函数。如果是完全执行的协程,任何函数都可以让暂停的协程继续执行。
如果将Generator函数当做协程,完全可以将多个需要互相协作的任务写成Generator函数,他们之间使用yield标识交换控制权。
Generator 函数执行产生的上下文环境,一旦遇到yield命令,就会暂时退出堆栈,但是并不消失,里面的所有变量和对象会冻结在当前状态。等到对它执行next命令时,这个上下文环境又会重新加入调用栈,冻结的变量和对象恢复执行。
Generator函数的多种用途
- 可以使异步操作来实现同步化表达
- 控制流管理
- 部署Iterator接口
- 做为数据结构
上述的介绍中,我们看到了generator是什么,下边我们看一下,目前中,我们使用最多的,generator函数的异步调用。
异步编程对于单线程的JavaScript无疑是十分重要的(可以笼统的将异步定义为不连续的执行)。之前的文章中,我们也说过,JavaScript中对于异步的实现,就是回调函数。我们之前也有使用过promise去进行死亡回调的改良,promise来使回调嵌套的表现形式更好了些。其实呢generator函数也可以用来实现异步回调的嵌套。
整个Generator函数就是一个封装的异步任务,或者说是异步任务的容器。异步操作需要暂停的地方,都用yield语句注明。除此之外,它还有两个特性,使它可以作为异步编程的完整解决方案:函数体内外的数据交换和错误处理机制。即为next方法还可以接收参数,向Generator函数体内输入数据。
Thunk函数
Thunk函数是自动执行Generator函数的一种方法。
对于以前的函数参数的求值计算,有两种计算方式,一种是传值调用,一种是传名调用。编辑器中的“传名调用”的实现,往往是将参数放到一个临时函数之中,再将这个临时函数传入函数体,这个临时函数就叫做Thunk函数。
JavaScript中使用的是传值调用,它的Thunk函数含义有所不同。再JavaScript中,替换的不是表达式,而是多参数函数的休整。
Thunk函数可以用于Generator函数的自动流程管理。即使Generator函数可以自动执行。
co模块
co模块用于Generator函数的自动执行。co函数返回一个Promise对象,因此可以用then方法添加回调函数。
使用了Generator函数之后,我们可以将多个异步嵌套的代码改为同步写异步,大大的简化了我们的代码量,以及代码的美观。
上边就是大概的ES中的Generator函数的介绍,我们可以使用Generator来实现 lazy evaluation,Iterator和实现异步调用同步的写法,但是其中我们面临的更多的还是generator的执行问题,下一篇我们来看一下generator是怎么实现async/await来控制异步。以及co模块的实现。
ES6的generator函数的更多相关文章
- ES6 学习 -- Generator函数
(1)语法说明:Generator函数其实是一个普通函数,其有两个特点,一是,function关键字与函数名之间有一个星号(*):二是Generator函数内部使用yield表达式,定义不同的状态,然 ...
- 【es6】Generator 函数
1. 基本概念 状态机,封装了多个内部状态 2. 应用 返回一个遍历器对象. 3. 代码形式 function* helloWorldGenertor() { yield 'hello'; yield ...
- ES6 - Note7:Generator函数
Generator函数 1.Generator函数是ES6增加的异步编程解决方案之一,与普通的函数行为完全不同,类似于一个状态机,内部封装了多个状态. 在函数定义的形式上,跟普通函数差不多,有两处不同 ...
- 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,它的 ...
随机推荐
- csrf
什么是CSRF: CSRF(Cross-site request forgery),中文名称:跨站请求伪造 攻击者盗用了你的身份,以你的名义发送恶意请求.CSRF能够做的事情包括:以你名义发送邮件,发 ...
- linux权限归属及特殊权限设置
访问权限:读取:允许查看内容 -read写入:允许修改内容 -write可执行:允许运行和切换 -excute(以上三点rwx共同决定最终权限)归属关系:所有者:拥有此文件/目录的用户 -user所属 ...
- ajax常用实例代码总结新手向参考(一)
http的交互方法有四种:get.post.put(增加数据).delete(删除数据) put和delete实现用的是get和post get方式 页面不能被修改,只是获取查询信息.但是提交的数 ...
- jqeury显示前几个,隐藏后几个,点击后隐藏前几个显示后几个
<script type="text/javascript"> $(".ul li").each(function(){ if($(this).in ...
- Hi3531支持2GByte内存
型号为K4B4G1646B-HCKO 1.修改DDRC_RNKCFG 为 0x142 2.修改arch/arm/mach-godnet/include/mach/vmalloc.h 扩大 vmallo ...
- Android APP开发入门教程-Button
代码编写 做好准备工作后,终于可以开始写我们的hello android了,在开始编写代码之前,我们先了解几个文件: res/layout/main.xml App主窗体布局文件,你的应用长什么样都在 ...
- SDL显示文字
前面教程里,我们只显示图片,没提到如何显示文字, SDL本身没有显示文字功能,它需要用扩展库SDL_ttf来显示文字.ttf是True Type Font的缩写,ttf是Windows下的缺省字体,它 ...
- vue cli创建的项目 当你后期使用了ES6语法,如何解决浏览器兼容问题
最近开发了一个项目,开发过程中,由于需要使用了async await ,于是发现,只有少数的浏览器支持,极大多数的浏览器是不支持这玩意的,在网上各种找解决方案,基本都是失败,最后总结了两个方案之后,尝 ...
- T470p VS 2017 上运行 VS 2015 + Qt 5.6.2 + GLSL 400
vs 2017 的qt设置可以按照这篇文章 注意,必须使用qt的安装程序进行安装,否则会出现意想不到的问题(不要简单地把qt的文件拷贝过来..血的教训) 显卡的问题 好不容易编译通过了,一运行报了一个 ...
- GridView 翻页 索引超出范围
事件回顾 今天GridView翻页时,又遇到错误:索引超出范围.必须为非负值并小于集合大小. 这是当时的PageIndexChanging和RowCommand两个事件的后台代码 protected ...