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就行,就好像函数在暂停后,继续执行。

原文发布于微信公众号 - 交互设计前端开发与后端程序设计(interaction_Designer)

原文发表时间:2017-09-26

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏微信公众号:Java团长

理解Java虚拟机体系结构

  众所周知,Java支持平台无关性、安全性和网络移动性。而Java平台由Java虚拟机和Java核心类所构成,它为纯Java程序提供了统一的编程接口,而不管下...

14360
来自专栏JetpropelledSnake

Python面试题之Python反射机制

 我们要导入另外一个模块,可以使用import.现在有这样的需求,我动态输入一个模块名,可以随时访问到导入模块中的方法或者变量,怎么做呢?

35920
来自专栏

go 语言的序列化与反序列化

与c 语言一样, 在网络编程中, go语言同样需要进行序列化与反序列化 在c语言中, 通常需要一块内存缓冲区用来收 发数据。缓冲区一般定义成char *buff...

35870
来自专栏后端技术探索

实用篇-无处不在的Location

location配置是nginx模块化配置中最出色的一个设计,几乎所有nginx的业务场景都要通过书写多个location配置来顺应业务需要。语法配置和执行规则...

12320
来自专栏自动化测试实战

接口测试基础——第7篇 简单的Python知识普及

32630
来自专栏微信公众号:Java团长

Java虚拟机类加载机制

看到这个题目,很多人会觉得我写我的java代码,至于类,JVM爱怎么加载就怎么加载,博主有很长一段时间也是这么认为的。随着编程经验的日积月累,越来越感觉到了解虚...

10820
来自专栏xingoo, 一个梦想做发明家的程序员

数字按照不同格式转换成字符串

  如果自己写函数,不使用itoa怎么判断呢?   我们用通常的办法,对数字进行每位的除商,得到后与字符'0'相加。 flag = 0; ...

213100
来自专栏Hongten

python开发_dbm_键值对存储_完整_博主推荐

============================================

11950
来自专栏Linyb极客之路

深入理解和探究Java类加载机制

java.lang.ClassLoader类的基本职责就是根据一个指定的类的名称,找到或者生成其对应的字节代码,然后从这些字节代码中定义出一个Java 类,即 ...

11930
来自专栏python3

python列表

"C:Program Files (x86)python3.6python.exe" D:/python3_study/list1.py

12130

扫码关注云+社区

领取腾讯云代金券