yield 原理篇
新版JS中,yield估计是最吸引人的新功能,特别是Node出来之后,大家被异步折腾的够呛,而借助于yield
可以用比较优雅的处理异步流程。 但是yield
关键字,早就出现在其他语言当中了,我知道的有python和c#。这篇从最基本的原理讲起,希望大家能更好的理解yield
。 关于yield
是什么,可以看这篇介绍
1.Iterators
先从迭代器模式讲起。简单地讲,迭代器是一种遍历集合的方式。它的接口很简单,一般拥有以下三个方法就可以了。
hasNext() //集合中是否还有下一个元素next() //迭代到下一个元素reset()//重置,我见到的代码一般是抛出异常,即一般不支持多次迭代
那么我们来实现一个简单的迭代器吧
function Range(min,max){//[min,max) return {
cur:min,
hasNext:function(){
return this.cur<max;
},
next:function(){
return this.cur++;
},
reset:function(){
throw new Error('unsupportted operation');
}
}}for(var iter = Range(1,10);iter.hasNext();){
i = iter.next();
console.log(i);}
对于迭代的过程,一般会做一些语法糖,然后用起来就很舒服了,像下面:
for(var i : Range(1,10)){
console.log(i);}
一个复杂的例子
function fib(){
return {
state :0,
cur :0,
prev1:-1,
prev2:-1,
hasNext:function(){
return true;
},
//fib数列,第一个是0,第二个是1,后面就是统一的迭代公式了 next:function(){
if(this.state==0){
this.cur = 0;
this.state=1;
}else if(this.state == 1){
this.cur =1;
this.prev2=0;
this.state=2;
}else{
this.prev1 = this.prev2;
this.prev2 =this.cur;
this.cur = this.prev1+this.prev2;
}
return this.cur;
}
//ignore reset funciton }}//这是无限序列,所以改造了一下,只生成8个数var fibIter = fib();for(var i = 0;i<8;i++){
console.log(fibIter.next());
if(fibIter.hasNext())
continue;}
这个例子可以展示迭代器模式更多的特点:
- 1.可以没有真正的集合(像Array),只要有相应的生成规则就行。这种情况下,没有内存的限制,因此可以表示无限序列
- 2.不调用next(),迭代器不进行迭代的,因此有延迟加载的特性。
- 3.迭代器,本质上是一个状态机,比如上面的fib,每个状态下,进行一些操作,然后进入下一个状态或维持状态不变。
Generators
迭代器模式是很常用的设计模式,但是实现起来,很多东西是程序化的;当迭代规则比较复杂时,维护迭代器内的状态,是比较麻烦的。 于是有了generator,何为generator,这里 说的很明确: Generators: a better way to build Iterators.
就是实现迭代器的更好的方式,借助 yield
关键字,可以更优雅的实现上面的fib数列。下面的代码需要环境支持 JS 1.7,如何让你的环境支持1.7,请参见http://html-js.com/article/1687
function* fib2(){
yield 0;//状态0,第一次调用next,返回0,并改变状态 yield 1;//状态1,第二次调用next,返回1,并改变状态
var p1 = 0
,p2 =1
,cur = p1+p2;
while(true){
yield cur;//状态2,后面调用next,返回相应的几个,状态不在改变
p1 = p2;
p2 = cur;
cur = p1+p2;
}}var fibIter2 = fib2();for(var i =0;i<8;i++){
console.log(fibIter2.next().value);}
对比上面自己实现的迭代器,应该可以看出,yield
是解释器给我们提供的语法糖,但是对比上下的代码,用yield
,更简洁,而且逻辑也更好懂。
**上面对于状态的描述,是我自己写的,编译器(解释器)不一定会生成一样的东西。这些原理,可以从反编译的C#代码看出来:yield的确会转化成相应的状态机。JS的实现可能不一样,但是对于理解yield的行为,是没有影响的
yield
与异步
那yield
,怎么解决异步的问题呢。 通过上面的分析,yield
之后,实际上本次调用就结束了,控制权实际上已经转到了外部调用了generator的next方法的函数,调用的过程中伴随着状态的改变。那么如果外部函数不继续调用next方法,那么yield
所在函数就相当于停在yield
那里了。所以把异步的东西做完,要函数继续执行,只要在合适的地方再次调用generator 的next就行,就好像函数在暂停后,继续执行。
- 图片上传预览js
- Isolation Forest算法实现详解
- css继承样式怎么控制?用选择器
- wordpress站内搜索结果页URL伪静态如何操作
- 如何实现大图居中超过的部分两边自动隐藏
- Ubuntu16.04安装后开发环境配置和常用软件安装
- wordpress如何屏蔽wp-json(禁用REST API)
- 贝叶斯系列——贝叶斯与其他统计流派的区别和联系
- bootstrap tab切换如何让鼠标移动自动切换内容
- css自动换行如何设置?url太长会撑开页面
- Histogram of Oriented Gridients(HOG) 方向梯度直方图
- 动态规划系列之最长递增子序列问题解答
- Git SSH Key 生成步骤
- 如何将wordpress所有文章批量改为已发布状态
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 最全解密微信红包随机算法(含代码实现)
- 两次死锁的分析
- 一次解决你的图像尺寸和定位问题。
- vuedraggable实现列表拖动排序
- 在 Xcode 中添加 Swift package 依赖
- 浅谈JavaScript中的apply,call和bind
- Git 的简单使用
- 移动端适配
- 《Algorithms Unlocked》读书笔记1——循环和递归
- 《Algorithms Unlocked》读书笔记2——二分查找和排序算法
- 《Algorithms Unlocked》读书笔记3——计数排序
- vue-element-admin
- 二叉树的递归算法
- mongoDB基本操作
- 一个 Vue + Node + MongoDB 博客系统