美文网首页
ES6:生成器(Generators)

ES6:生成器(Generators)

作者: 每天写写代码 | 来源:发表于2018-05-13 01:03 被阅读0次

    生成器

    先看下面的例子

    function* quips(name) {
        yield "hello " + name + "!";
        yield "i hope you are enjoying the blog posts";
        if (name.startsWith("X")) {
            yield "it's cool how your name starts with X, " + name;
        }
        yield "see you later!";
    }
    

    上面的函数就是生成器函数,和普通函数的不同在于:

    • 使用function*定义生成器函数,而普通函数使用function
    • 生成器函数里面有yield关键字

    yield关键字是用来做什么的?

    运行下下面的代码:

    var iter = quips("Xjorendorff");
    
    console.log(iter.constructor);
    
    //第1个yield
    var ret = iter.next();
    console.log(ret);
    
    //第2个yield
    ret = iter.next();
    console.log(ret);
    
    console.log("continue ...")
    
    //第3个yield
    ret = iter.next();
    console.log(ret);
    
    //第4个yield
    ret = iter.next();
    console.log(ret);
    

    结果:

    GeneratorFunction {}
    { value: 'hello Xjorendorff!', done: false }
    { value: 'i hope you are enjoying the blog posts', done: false }
    continue ...
    { value: 'it\'s cool how your name starts with X, Xjorendorff',
      done: false }
    { value: 'see you later!', done: false }
    
    

    可以得出的结论是:

    • 在生成器函数中,yield关键字可以有多个
    • quips("Xjorendorff")只是返回一个暂停的生成器对象
    • 如果不调用生成器函数对象的next()方法,生成器的内部代码不会被执行
    • 每调用一次next()方法,只执行完下一个yield关键字修饰的语句,调用完成就挂起,继续执行生成器函数外的其他的语句。
    • 多执行一次next()语句才能执行是否执行完毕。如果不多执行一次,后面的普通代码无法执行。

    可以非常确定的说,生成器里的代码都是单线程的,指示生成器内部暂停,生成器对象维护自己的栈帧状态。

    大家可能会有疑问,生成器的作用是什么?

    生成器是一种迭代器

    ES6中的迭代器不仅仅就是一个内置类,它还是是语言的一个扩展点,如果你想实现自己的迭代器,只需要实现[Symbol.iterator]()next()函数即可。

    先看一个例子,自己实现迭代器:

    class RangeIterator {
        constructor(start, stop) {
            this.value = start;
            this.stop = stop;
        }
    
        [Symbol.iterator]() { return this; }
    
        next() {
            var value = this.value;
            if (value < this.stop) {
                this.value++;
                return {done: false, value: value};
            } else {
                return {done: true, value: undefined};
            }
        }
    }
    
    // Return a new iterator that counts up from 'start' to 'stop'.
    function range(start, stop) {
        return new RangeIterator(start, stop);
    }
    ``
    使用迭代器:
    ```javascritp
    // This should "ding" three times
    for (var value of range(0, 3)) {
        console.log("Ding! at floor #" + value);
    }
    

    结果:

    Ding! at floor #0
    Ding! at floor #1
    Ding! at floor #2
    

    同样的功能,看生成器如何实现的:

    function* range(start, stop) {
        for (var i = start; i < stop; i++)
            yield i;
    }
    

    调用:

    // This should "ding" three times
    for (var value of range(0, 3)) {
        console.log("Ding! at floor #" + value);
    }
    

    结果:

    Ding! at floor #0
    Ding! at floor #1
    Ding! at floor #2
    

    结果完全一样。

    生成器为什么有这样的能力?

    因为生成器就是一种迭代器,所有的生成器都内部实现了next()[Symbol.iterator]()函数。所以可以使用for-of迭代。通过yield返回那次迭代的值即可。

    通过上面的例子,我们可以得出下面的结论:

    • 可以用生成器更容易的写一个迭代器
    • 可以写更简单的循环
    • 可以写一些迭代相关的工具:比如过滤器,对迭代的特殊处理,过滤器的例子如下
    function* filter(test, iterable) {
      for (var item of iterable) {
        if (test(item))
          yield item;
      }
    }
    

    生成器和异步

    js的异步调用有多痛苦不用多说了。
    有很多解决异步问题的方案,比如Deffed/Promise,Promise nodejs已原生支持。

    那么生成器是如何处理异步的呢?

    TODO

    参考

    ES6 In Depth: Generators

    相关文章

      网友评论

          本文标题:ES6:生成器(Generators)

          本文链接:https://www.haomeiwen.com/subject/zzlkdftx.html