Generator函数的含义

Generator 与状态机

Generator 是实现状态机的最佳结构。比如,下面的clock函数就是一个状态机。

  1. var ticking = true;
  2. var clock = function() {
  3. if (ticking)
  4. console.log('Tick!');
  5. else
  6. console.log('Tock!');
  7. ticking = !ticking;
  8. }

上面代码的clock函数一共有两种状态(TickTock),每运行一次,就改变一次状态。这个函数如果用 Generator 实现,就是下面这样。

  1. var clock = function* () {
  2. while (true) {
  3. console.log('Tick!');
  4. yield;
  5. console.log('Tock!');
  6. yield;
  7. }
  8. };

上面的 Generator 实现与 ES5 实现对比,可以看到少了用来保存状态的外部变量ticking,这样就更简洁,更安全(状态不会被非法篡改)、更符合函数式编程的思想,在写法上也更优雅。Generator 之所以可以不用外部变量保存状态,是因为它本身就包含了一个状态信息,即目前是否处于暂停态。

Generator 与协程

协程(coroutine)是一种程序运行的方式,可以理解成“协作的线程”或“协作的函数”。协程既可以用单线程实现,也可以用多线程实现。前者是一种特殊的子例程,后者是一种特殊的线程。

(1)协程与子例程的差异

传统的“子例程”(subroutine)采用堆栈式“后进先出”的执行方式,只有当调用的子函数完全执行完毕,才会结束执行父函数。协程与其不同,多个线程(单线程情况下,即多个函数)可以并行执行,但是只有一个线程(或函数)处于正在运行的状态,其他线程(或函数)都处于暂停态(suspended),线程(或函数)之间可以交换执行权。也就是说,一个线程(或函数)执行到一半,可以暂停执行,将执行权交给另一个线程(或函数),等到稍后收回执行权的时候,再恢复执行。这种可以并行执行、交换执行权的线程(或函数),就称为协程。

从实现上看,在内存中,子例程只使用一个栈(stack),而协程是同时存在多个栈,但只有一个栈是在运行状态,也就是说,协程是以多占用内存为代价,实现多任务的并行。

(2)协程与普通线程的差异

不难看出,协程适合用于多任务运行的环境。在这个意义上,它与普通的线程很相似,都有自己的执行上下文、可以分享全局变量。它们的不同之处在于,同一时间可以有多个线程处于运行状态,但是运行的协程只能有一个,其他协程都处于暂停状态。此外,普通的线程是抢先式的,到底哪个线程优先得到资源,必须由运行环境决定,但是协程是合作式的,执行权由协程自己分配。

由于 JavaScript 是单线程语言,只能保持一个调用栈。引入协程以后,每个任务可以保持自己的调用栈。这样做的最大好处,就是抛出错误的时候,可以找到原始的调用栈。不至于像异步操作的回调函数那样,一旦出错,原始的调用栈早就结束。

Generator函数是 ES6 对协程的实现,但属于不完全实现。Generator函数被称为“半协程”(semi-coroutine),意思是只有 Generator函数的调用者,才能将程序的执行权还给 Generator函数。如果是完全执行的协程,任何函数都可以让暂停的协程继续执行。

如果将 Generator函数当作协程,完全可以将多个需要互相协作的任务写成 Generator函数,它们之间使用yield表示式交换控制权。

Generator 与上下文

JavaScript 代码运行时,会产生一个全局的上下文环境(context,又称运行环境),包含了当前所有的变量和对象。然后,执行函数(或块级代码)的时候,又会在当前上下文环境的上层,产生一个函数运行的上下文,变成当前(active)的上下文,由此形成一个上下文环境的堆栈(context stack)。

这个堆栈是“后进先出”的数据结构,最后产生的上下文环境首先执行完成,退出堆栈,然后再执行完成它下层的上下文,直至所有代码执行完成,堆栈清空。

Generator函数不是这样,它执行产生的上下文环境,一旦遇到yield命令,就会暂时退出堆栈,但是并不消失,里面的所有变量和对象会冻结在当前状态。等到对它执行next命令时,这个上下文环境又会重新加入调用栈,冻结的变量和对象恢复执行。

  1. function *gen() {
  2. yield 1;
  3. return 2;
  4. }
  5. let g = gen();
  6. console.log(
  7. g.next().value,
  8. g.next().value,
  9. );

上面代码中,第一次执行g.next()时,Generator函数gen的上下文会加入堆栈,即开始运行gen内部的代码。等遇到yield 1时,gen上下文退出堆栈,内部状态冻结。第二次执行g.next()时,gen上下文重新加入堆栈,变成当前的上下文,重新恢复执行。

es6 Generator函数的含义相关推荐

  1. [ES6] Generator 函数

    [ES6] Generator 函数 Generator 函数与普通函数的区别 执行机制 Generator 函数返回的遍历器对象的方法 循环遍历器 Iterator 对象的方法 next 方法 re ...

  2. Generator 函数的含义与用法

    异步编程对 JavaScript 语言太重要.JavaScript 只有一根线程,如果没有异步编程,根本没法用,非卡死不可. 以前,异步编程的方法,大概有下面四种. 回调函数 事件监听 发布/订阅 P ...

  3. es6 Generator函数的应用

    Generator函数的应用 es6 Generator 可以暂停函数执行,返回任意表达式的值.这种特点使得 Generator 有多种应用场景. 异步操作的同步化表达 Generator函数的暂停执 ...

  4. es6 Generator函数的this

    Generator函数的this Generator函数总是返回一个遍历器,ES6 规定这个遍历器是Generator函数的实例,也继承了Generator函数的prototype对象上的方法. fu ...

  5. es6 Generator函数概述

    概述 什么是Generator函数 Generator函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同.本章详细介绍 Generator函数的语法和 API,它的异步编程应用请看 ...

  6. ES6——Generator 函数的语法

    Generator 函数是一个状态机,封装了多个内部状态.执行 Generator 函数会返回一个遍历器对象,也就是说,Generator 函数除了状态机,还是一个遍历器对象生成函数.返回的遍历器对象 ...

  7. ES6 Generator函数

    一.基本概念 Generator 函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同. Generator 函数有多种理解角度. 语法上,Generator 函数是一个状态机,封装 ...

  8. 理解 ES6 Generator 函数

    Generator函数是ES6引入的新型函数,用于异步编程,跟Promise对象联合使用的话会极大降低异步编程的编写难度和阅读难度. Generator函数跟普通函数的写法有非常大的区别: 一是,fu ...

  9. ES6 Generator函数 深入应用

    前提 线程与进程 在操作系统(此处说的系统是引入了线程概念的系统)中一个应用要想执行必须有一定的执行资源,而执行资源大致分为两个部分一个是执行时需要用的内存,一个是CPU执行权.而系统分配给每个应用的 ...

最新文章

  1. c语言mysql源代码,永盈会-官方网站
  2. What every programmer should know about memory 笔记
  3. 字典与文本文档的转换
  4. 静态路由默认路由的配置
  5. 来领资料咯!计算机专业教科书礼包
  6. 深度学习(十五)基于级联卷积神经网络的人脸特征点定位
  7. Hadoop笔记——技术点汇总
  8. golang连接mysql操作示例增删改查
  9. 那些年,我们一起追过的seo培训!
  10. GPU卡的主流调度平台
  11. strick-footer 粘边布局
  12. Vue和ElementUI第二天
  13. 上周热点回顾(12.5-12.11)
  14. 计算机网络——网络安全(湖科大 教书匠)
  15. WLAN AP安全策略中WPA认证与WPA2认证的差异
  16. 面向对象编程是什么意思
  17. Lesson 018 —— python 集合
  18. Si39333有源 RFID 标签
  19. 《蒹葭》-- 选自《诗经·国风·秦风》
  20. XY618 4G 安卓智能核心板(虎贲T618平台)

热门文章

  1. 一分钟系列:详解阿里云68款产品【热点问题+用户实践】
  2. iOS开发-仿大众点评iPad侧边导航栏
  3. Vim - 奇技淫巧
  4. ByteBuffer 转 InputStream
  5. 读书笔记之101个脚本之No.8
  6. 五问唐骏:泡妞真的如你说的那么容易?
  7. 事务学习总结(2)——spring事务
  8. Python 读入Excel表时如何判空NaN
  9. 线性代数:线性方程组的解
  10. 我发起了一个 ILBC 的 子项目 EScript