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,它的 ...
随机推荐
- 转: JavaScript 获取对象属性和方法
一.获取对象属性和方法 Object.keys()for in 返回对象的可枚举属性和方法的名称数组. Object.getOwnPropertyNames() 返回的数组的所有属性(可枚举或不可枚举 ...
- 搬砖的也能学Python----if - elif 语句
引入:如果平时执行的过程超过两个分支,则使用if-elif语句 if-elif 语句结构 if 判断条件: 要执行的代码 elif 判断条件: 要执行的代码 -- else: 要执行的代码 判断条件: ...
- 【linux之挂载,Raid,LVM】
一.挂载,卸载 挂载:将新的文件系统关联至当前根文件系统卸载:将某文件系统与当前根文件系统的关联关系移除 cat /etc/mtab 存储着已经挂载的文件系统 (跟 mount 一样) mount:显 ...
- XP硬盘读写速度很慢的解决方法
05购入的电脑,今日仍在发挥余热,但系统速度慢得出奇.今日检测了硬盘读写速度还不到2m/s,实在令人难以接受.一查之下,硬盘被置为PIO模式了,难怪. 用以下方法得以解决: 1.对桌面"我的 ...
- Java Web项目(Extjs)报错一
1.Java Web(Extjs)项目报错一 usage: java org.apache.catalina.startup.Catalina [ -config {pathname} ] [ -no ...
- Flex中TitleWindow传值
Flex中TitleWindow传值 1.设计思路 (1)新建一个DataGrid,在其中最后一列加入三个按钮:新增.修改和删除: (2)点击新增按钮,可以将表格新增一行: (3)单击"修改 ...
- ajax页面跳转(后台返回的是一个url地址,或者自己传进去的是url地址)
function modifyMerchantInfo(merchant_code) { $.ajax({ url: '/intra/crm/merchant/OrderMgr.htm?method= ...
- @SuppressWarnings("unchecked")(解决标准的后台HttpServletRequest request, HttpServletResponse response)格式
在springmvc的应用中有些限制会出现必须是 public void save(HttpServletRequest request, HttpServletResponse response) ...
- Windows DLL资料整理
1.使用Visual C++ 6.0创建dll 2. 函数的调用规则(__cdecl,__stdcall,__fastcall,__pascal) 要点: 1. 如果你的程序中没有涉及可变参数,最好使 ...
- 最新的 iOS 申请证书与发布流程
申请流程. 1. 申请钥匙串文件 进入 (Launchpad),找到 (我的是在其他里面找到的),运行后再左上角 存储在桌面就好了,然后就完成退出钥匙串工具就可以了. 2.申请开发证书,发布证书 ...