生成器 Generator 使得函数可以通过 yield 暂停,并且暂停还可以通信,通信结束后可以继续执行。其上下文会被保存。

生成器 Generator

function* 声明定义了一个生成器函数,返回一个 Generator 对象。

function* name(param0) {
  statements;
}

fucntion* name(param0, param1, /*...,*/ paramN) {
  statements;
}

调用一个生成器函数不会被立即执行,而是返回一个可迭代的生成器对象。当该迭代器的 next() 方法被调用,该生成器才会被执行,并返回第一个 yield 的表达式。该迭代器返回一个包含了一个 value 属性的值和一个 done 的布尔值的对象。

fucntion* generator() {
  yield 10;
}

const it = generator();
const res = it.next(); // res = { value: 10, done: true }

return 语句在生成器里被执行的时候,将使该生成器结束(done 变成 true)。

yield

yield 操作符用来暂停和恢复生成器函数。

[rv] = yield[expression];

yield 关键字暂停生成器函数的执行,并且紧随在 yield 关键字后的表达式会被返回。可以当作生成器独有的 return 关键字。

一旦生成器函数在 yield 表达式暂停,生成器将会被暂停直到下一次生成器的 next 方法调用。

消息传递

除了能够接受参数并提供返回值之外,生成器甚至提供了更强大的内建消息输入输出能力,通过 yield 和 next() 实现。

function* foo(x) {
  const y = x * (yield);
  return y;
}
const it = foo(6);
// 启动 foo()
it.next();
const res = it.next(7); // res = { value: 42, done: true }

在执行语句 const y = x * (yield),会遇到 yield 表达式,就会暂停函数。并在本质上要求调用代码为 yield 表示式提供一个结果值。调用 it.next(7),将值 7 传回作为被暂停的 yield 表达式的结果。 一步一步理解 Generator 函数的原理 在通过内建消息输入的时候,需要调用的 next() 调用要比 yield 多一个。因为第一个 next 总是启动一个生成器。

原理

Generator 函数是协程在 ES6 的实现,遇到 yield 命令会暂停,将执行权交出去,等执行权回来之后继续从暂停的地方开始执行。

协程(Coroutines)是一种比线程更加轻量级的存在,一个线程可以拥有多个协程。

总结下来:

  • 一个线程存在多个线程
  • Generator 函数是协程在 ES6 的实现
  • yield 挂起协程,next 唤起协程

参考链接