Generator和yield 分析

  • 项目中使用了koa,最近在学习koa的源码,先把这些东西都写下来,免得以后忘记了。

  • koa源码学习前先注意下面这三个概念

    1. generator function (生成器函数)

    2. generator (生成器)

    3. yield

下面是一坨很简单的代码

function *gen() {

    yield 'sd';
}
var g = gen();

上面的代码中 gen是一个generator function, g是一个generator, yield 只是一个语法糖,下面会具体介绍


iterator和generator特性借鉴于Python, Ruby, smalltalk,
本来用于方便访问容器内各个元素. 该特性需要node v0.11.9并开启–harmony特性才能使用,
在chrome(29+)浏览器中需要在chrome://flags/ 开启Enable Experimental JavaScript选项, 然后重启.

generator

下面先介绍一下迭代器的概念,英文版本的点击这里

一个迭代器(对象)会有一个名为 next 的方法,
调用该方法后会返回一个拥有两个属性的对象, 一个是 value 属性, 值可以是任意值, 以及一个 done 属性, 布尔值,
表示该迭代器是否已经被迭代完毕,
类似{done: true/false, value: returnValue}结构数据    小贴士:String, Array, TypedArray, Map and Set 都是内建的迭代器,
一些表达式希望后面是iterable的,比如for of , yield*, 和析构复制[..."abcd"] //看下这个语句返回什么呢?
此外,generator 还有一个throw 方法,可以进行异常处理

generator 就是一个迭代器, 含有next方法
每当调用 next() 的时候,generator function内部就会执行直到遇到下一个 yield 语句,然后暂停在那里,并返回一个对象。

generator function

普通函数添加*号后则成为了成为了生成器函数了。

// 定义生成器函数

function *enumerable(msg){console.log(msg)var msg1 = yield msg + '  after 'console.log(msg1)var msg2 = yield msg1 + ' after'try{var msg3 = yield msg2 + 'after'console.log('ok')}catch(e){console.log(e)}console.log(msg2 + ' over')
}// 初始化迭代器
var enumerator = enumerable('hello')
var ret = enumerator.next() // 控制台显示 hello,ret的值{value:'hello after',done:false}
ret =  enumerator.next('world') // 控制台显示 world,ret的值{value:'world after',done:false}
ret = enumerator.next('game') // 控制台显示game,ret的值{value:'game after',done:false}
// 抛出异常信息
ret = enumerator.throw(new Error('test')) //
//控制台显示new Error('test')信息,然后显示game over。ret的值为{done:true}

生成器函数的行为与普通函数并不相同,表现为如下3点:

  1. 通过new运算符或函数调用的形式调用生成器函数,均会返回一个生成器实例;

  2. 通过new运算符或函数调用的形式调用生成器函数,均不会马上执行函数体的代码;

  3. 必须调用生成器实例的next方法才会执行生成器函数体的代码。

关键字yield

用于马上退出代码块并保留现场,当执行迭代器的next函数时,则能从退出点恢复现场并继续执行下去。

一旦在 yield expression 处暂停,  除非外部调用生成器的 next() 方法,否则生成器的代码将不能继续执行.这使得可以对生成器的执行以及渐进式的返回值进行直接控制.

下面有2点需要注意:

  1. yield后面的表达式将作为迭代器next函数的返回值;

  2. 迭代器next函数的入参将作为yield的返回值(有点像运算符)。

针对上面的例子,
var ret = enumerator.next()// {value:'hello after',done:false}
enumerator.next('msg1 result');//这时候msg1的值是 msg1 result;

yield* 和 yield的区别

yield* 一个可迭代对象,就相当于把这个可迭代对象的所有迭代值分次 yield 出去。
yield* 表达式本身的值就是当前可迭代对象迭代完毕时的那个返回值(也就是迭代器的迭代值的 done 属性为 true 时 value 属性的值)。

function* g1() {

   yield 2;yield 3;yield 4;

}

function* g2() {

   yield 1;yield* g1();yield 5;

}

var iterator = g2();
console.log(iterator.next()); // { value: 1, done: false }
console.log(iterator.next()); // { value: 2, done: false }
console.log(iterator.next()); // { value: 3, done: false }
console.log(iterator.next()); // { value: 4, done: false }
console.log(iterator.next()); // { value: 5, done: false }
console.log(iterator.next()); // { value: undefined, done: true}

//返回值例子

function* g4() {

   yield* [1, 2, 3];return "foo";

}
var result;
function* g5() {

   result = yield* g4();

}
var iterator = g5();
console.log(iterator.next()); // { value: 1, done: false }
console.log(iterator.next()); // { value: 2, done: false }
console.log(iterator.next()); // { value: 3, done: false }
console.log(iterator.next()); // { value: undefined, done: true},
此时 g4() 返回了 { value: "foo", done: true }
console.log(result); // "foo"

具体可以参考yield *

异常处理

可以通过throw 抛出异常,在外层try catch, 具体可以参考这里

function *foo() {

try {yield 2;
}
catch (err) {console.log( "foo caught: " + err );
}yield; // pause// now, throw another error
throw "Oops!";

}

function *bar() {

yield 1;
try {yield *foo();
}
catch (err) {console.log( "bar caught: " + err );
}

}
var it = bar();
it.next(); // { value:1, done:false }
it.next(); // { value:2, done:false }
it.throw( "Uh oh!" ); // will be caught inside foo()
// foo caught: Uh oh!
it.next(); // { value:undefined, done:true } --> No error here!
// bar caught: Oops!

其他

generator 需要不停地调用next方法,但是在项目中我们也没有手动的调用next方法,这是为什么呢?........

很牛的co模块就要登场了,请翻看下一篇

参考文章

https://developer.mozilla.org/zh/docs/Web/JavaScript/Guide/Iterators_and_Generators
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/yield
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/yield*

koa源码分析-generator和yield分析相关推荐

  1. Koa源码分析(二) -- co的实现

    Abstract 本系列是关于Koa框架的文章,目前关注版本是Koa v1.主要分为以下几个方面: Koa源码分析(一) -- generator Koa源码分析(二) -- co的实现 Koa源码分 ...

  2. 老李推荐:第5章5节《MonkeyRunner源码剖析》Monkey原理分析-启动运行: 获取系统服务引用 1...

    老李推荐:第5章5节<MonkeyRunner源码剖析>Monkey原理分析-启动运行: 获取系统服务引用 上一节我们描述了monkey的命令处理入口函数run是如何调用optionPro ...

  3. 老李推荐:第6章1节《MonkeyRunner源码剖析》Monkey原理分析-事件源-事件源概览 1...

    老李推荐:第6章1节<MonkeyRunner源码剖析>Monkey原理分析-事件源-事件源概览 在上一章中我们有简要的介绍了事件源是怎么一回事,但是并没有进行详细的描述.那么往下的这几个 ...

  4. 老李推荐:第6章6节《MonkeyRunner源码剖析》Monkey原理分析-事件源-事件源概览-命令队列...

    老李推荐:第6章6节<MonkeyRunner源码剖析>Monkey原理分析-事件源-事件源概览-命令队列 事件源在获得字串命令并把它翻译成对应的MonkeyEvent事件后,会把这些事件 ...

  5. Unity3D RPG角色扮演游戏源码(上下)-----源代码分析----01-----主角人物动画

    在源代码的里面有fbx格式的模型文件,发现有2个文件,一个是骨骼动画文件,可以分割为多个动画片段,还有一个是模型文件,但是没有动画,但是可以导入分割好的动画片段到动画元素里面, 按照下面的说明,分割了 ...

  6. Unity3D RPG角色扮演游戏源码(上下)-----源代码分析----04--修改菜单窗口

    Unity3D RPG角色扮演游戏源码(上下)-----源代码分析----04--修改菜单Shop窗口 此脚本用于创建商店以销售商品 --------------------------------- ...

  7. mybatis源码之执行insert代码分析

    系列文档: mybatis源码之创建SqlSessionFactory代码分析 mybatis源码之创建SqlSessionFactory代码分析 - mapper xml解析 mybatis源码之执 ...

  8. Android 源码 Camera2 预览流程分析四

    <Android 源码 Camera2 预览流程分析二>中进行了流启动,这是调用 QCamera3Channel start() 方法实现的,对应于 HAL_PIXEL_FORMAT_YC ...

  9. 直播开篇——电商直播系统源码直播场景和技术分析

    一.直播场景和技术分析 好吧,既然你们非要搞什么直播,我就开始写写直播吧,怪不得WebRTC是下一代关键技术,直播的一些业务页必须要用WebRTC来实现 1. 电商直播系统源码场景分析 秀场直播 这个 ...

最新文章

  1. TFS 无法签入或自动签出 解决方法 【强制撤销签出无效】
  2. python开发安卓程序-用python开发android应用(1)
  3. 搜索引擎 ElasticSearch 之 步步为营2 【基础概念】
  4. 函数传参string_JavaScript 高阶函数入门浅析
  5. android ripple 大小,Android L限制Ripple水波纹范围大小
  6. 测试环境搭建mysql数据库_软件测试环境的搭建系列:[2] MySQL数据库的安装
  7. c统计查找的字符串个数
  8. Mount挂载命令使用方法
  9. CCF NOI1075 F函数
  10. js简单屏蔽鼠标右键实现方式
  11. 基于cocos2d-x引擎的游戏框架设计
  12. 交换机和集线器的区别是什么?
  13. TX2入门(10)——TensorRT(1)(tx2端inference)
  14. 【转】​“八段锦”养生:通经络,补气血,简单8个动作调理全身脏腑!
  15. [zz] 基于sinc的音频重采样(一):原理
  16. uni-app修改代码,微信开发者工具不更新
  17. 在CentOS上安装和配置OpenNebula入门实例
  18. 搞机:window10安装Linux子系统(WSL)及迁移到非系统盘
  19. 网络入侵防御系统全解
  20. 降维技术 (Dimensionality Reduction)

热门文章

  1. python中import问题
  2. 关于xfce中桌面没法显示回收站以及thunar中无法进行卷管理的解决办法
  3. 添加MD5 密码加密
  4. CDays-3 习题二 (字典及文件读取练习)及相关内容解析。Python 基础教程
  5. MYSQL 5.1自动安装脚本
  6. 思科cisco路由器动态路由协议配置方法
  7. C#的WinForm程序应用了XP主题样式之后,ShowDialog方法出现问题的解决
  8. Android学习之简单地使用碎片
  9. Springboot2 自定义异常处理
  10. python绘制基因结构图_Python调用graphviz绘制结构化图形网络示例