美文网首页
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