生成器

函数暂停然后再次恢复的能力,不是异步函数所独有的。 JavaScript 也有一个称为生成器函数的特性。 这些都是相似的,但没有Promise

当用function*定义一个函数(在函数后面加星号)时,它就成为一个生成器。 当你调用一个生成器时,它将返回一个迭代器,我们在第 6 章已经看到了它。

  1. function* powers(n) {
  2. for (let current = n;; current *= n) {
  3. yield current;
  4. }
  5. }
  6. for (let power of powers(3)) {
  7. if (power > 50) break;
  8. console.log(power);
  9. }
  10. // → 3
  11. // → 9
  12. // → 27

最初,当你调用powers时,函数在开头被冻结。 每次在迭代器上调用next时,函数都会运行,直到它碰到yield表达式,该表达式会暂停它,并使得产生的值成为由迭代器产生的下一个值。 当函数返回时(示例中的那个永远不会),迭代器就结束了。

使用生成器函数时,编写迭代器通常要容易得多。 可以用这个生成器编写group类的迭代器(来自第 6 章的练习):

  1. Group.prototype[Symbol.iterator] = function*() {
  2. for (let i = 0; i < this.members.length; i++) {
  3. yield this.members[i];
  4. }
  5. };

不再需要创建一个对象来保存迭代状态 - 生成器每次yield时都会自动保存其本地状态。

这样的yield表达式可能仅仅直接出现在生成器函数本身中,而不是在你定义的内部函数中。 生成器在返回(yield)时保存的状态,只是它的本地环境和它yield的位置。

异步函数是一种特殊的生成器。 它在调用时会产生一个Promise,当它返回(完成)时被解析,并在抛出异常时被拒绝。 每当它yieldawait)一个Promise时,该Promise的结果(值或抛出的异常)就是await表达式的结果。