ES6:生成器(Generators)

2018-05-13  本文已影响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!";
}

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

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 }

可以得出的结论是:

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

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

生成器是一种迭代器

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

上一篇下一篇

猜你喜欢

热点阅读