博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
koa源码分析-generator和yield分析
阅读量:7210 次
发布时间:2019-06-29

本文共 3839 字,大约阅读时间需要 12 分钟。

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"

具体可以参考

异常处理

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

function *foo() {

try {    yield 2;}catch (err) {    console.log( "foo caught: " + err );}yield; // pause// now, throw another errorthrow "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模块就要登场了,请翻看下一篇

参考文章

*

转载地址:http://jcgum.baihongyu.com/

你可能感兴趣的文章
在线服务的黑天鹅(转)
查看>>
SLF4J warning or error messages and their meanings(转)
查看>>
为什么生产环境运行系统?
查看>>
MySQL使用总结(持续更新中 …)
查看>>
拨打电话
查看>>
Linux下安装mysql
查看>>
排序算法(2)—选择排序
查看>>
C++(实验六)
查看>>
EBS后台取消死锁检查代码和取消死锁会话步骤---经验
查看>>
[置顶] Gridview中弹出层前台取值避免了刷新,easyui+Jquery
查看>>
Oracle BIEE11G --- ADF_IFRAME
查看>>
Java 连接数据库
查看>>
部分 TCP 参数简介
查看>>
[转]java annotation 手册
查看>>
不安装oracle客户端也可以使用pl/sql developer
查看>>
4、在Shell程序中的使用变量
查看>>
AndroidのListView之滑动列表项(点击事件和滑动事件共存)
查看>>
pygtk手记(1)
查看>>
YOUYOU深入学习Ganglia之三(gmetad的软件架构)
查看>>
poj1483 It's not a Bug, It's a Feature!
查看>>