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函数的更多相关文章

  1. ES6 学习 -- Generator函数

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

  2. 【es6】Generator 函数

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

  3. ES6 - Note7:Generator函数

    Generator函数 1.Generator函数是ES6增加的异步编程解决方案之一,与普通的函数行为完全不同,类似于一个状态机,内部封装了多个状态. 在函数定义的形式上,跟普通函数差不多,有两处不同 ...

  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. 转: JavaScript 获取对象属性和方法

    一.获取对象属性和方法 Object.keys()for in 返回对象的可枚举属性和方法的名称数组. Object.getOwnPropertyNames() 返回的数组的所有属性(可枚举或不可枚举 ...

  2. 搬砖的也能学Python----if - elif 语句

    引入:如果平时执行的过程超过两个分支,则使用if-elif语句 if-elif 语句结构 if 判断条件: 要执行的代码 elif 判断条件: 要执行的代码 -- else: 要执行的代码 判断条件: ...

  3. 【linux之挂载,Raid,LVM】

    一.挂载,卸载 挂载:将新的文件系统关联至当前根文件系统卸载:将某文件系统与当前根文件系统的关联关系移除 cat /etc/mtab 存储着已经挂载的文件系统 (跟 mount 一样) mount:显 ...

  4. XP硬盘读写速度很慢的解决方法

    05购入的电脑,今日仍在发挥余热,但系统速度慢得出奇.今日检测了硬盘读写速度还不到2m/s,实在令人难以接受.一查之下,硬盘被置为PIO模式了,难怪. 用以下方法得以解决: 1.对桌面"我的 ...

  5. Java Web项目(Extjs)报错一

    1.Java Web(Extjs)项目报错一 usage: java org.apache.catalina.startup.Catalina [ -config {pathname} ] [ -no ...

  6. Flex中TitleWindow传值

    Flex中TitleWindow传值 1.设计思路 (1)新建一个DataGrid,在其中最后一列加入三个按钮:新增.修改和删除: (2)点击新增按钮,可以将表格新增一行: (3)单击"修改 ...

  7. ajax页面跳转(后台返回的是一个url地址,或者自己传进去的是url地址)

    function modifyMerchantInfo(merchant_code) { $.ajax({ url: '/intra/crm/merchant/OrderMgr.htm?method= ...

  8. @SuppressWarnings("unchecked")(解决标准的后台HttpServletRequest request, HttpServletResponse response)格式

    在springmvc的应用中有些限制会出现必须是 public void save(HttpServletRequest request, HttpServletResponse response) ...

  9. Windows DLL资料整理

    1.使用Visual C++ 6.0创建dll 2. 函数的调用规则(__cdecl,__stdcall,__fastcall,__pascal) 要点: 1. 如果你的程序中没有涉及可变参数,最好使 ...

  10. 最新的 iOS 申请证书与发布流程

    申请流程. 1. 申请钥匙串文件 进入  (Launchpad),找到   (我的是在其他里面找到的),运行后再左上角 存储在桌面就好了,然后就完成退出钥匙串工具就可以了. 2.申请开发证书,发布证书 ...