19

Node.js 现在有生成器。

我的理解是,生成器可用于编写看起来更加线性的代码,并避免回调地狱和末日风格编码的金字塔。

所以到目前为止,我的理解是在生成器内部,代码执行直到它到达“yield”语句。生成器函数的执行此时暂停。该yield语句指定可能是函数的返回值。通常这将是一个阻塞 I/O 函数——通常需要异步执行的函数。

yield 的返回函数被返回给任何称为生成器的东西。

我的问题是,此时会发生什么?究竟是什么执行了 yield 返回的阻塞 I/O 函数?

编写看起来是线性的生成器/产量代码是否正确,需要有一种特定类型的函数来调用生成器,一个循环通过生成器并执行产量返回的每个异步函数并返回的函数异步函数的结果返回到生成器?

我仍然不清楚 yield 返回的异步函数是如何执行的。如果是由调用生成器的函数执行的,是异步执行的吗?我猜是因为否则会导致阻塞行为。

总结我的问题:

  1. 要使用生成器编写“线性”异步代码,是否有必要有一个调用函数来迭代生成器,将产生的函数作为回调执行并将回调的结果返回到生成器?
  2. 如果问题 1 的答案是肯定的,那么产生的函数究竟是如何执行的——异步执行?

任何人都可以对整个过程的工作方式提供更好的概述/总结吗?

4

3 回答 3

13

使用生成器编写异步代码时,您正在处理两种类型的函数:

  • 用 . 声明的普通函数function。这些函数不能产生。你不能以同步的方式编写异步代码,因为它们会运行到完成;您只能通过回调处理异步完成(除非您调用node-fibers库或代码转换等额外功能)。
  • 用 . 声明的生成器函数function*。这些函数可以产生。您可以在其中以同步样式编写异步代码,因为它们可以产生。但是您需要一个伴随函数来创建生成器,处理回调并在每次回调触发时通过调用来恢复生成器。next

有几个实现伴随函数的库。在大多数这些库中,伴随函数一次处理一个,并且您必须在代码中的function*每个函数周围放置一个包装器。function*星系库(我写的)有点特别,因为它可以在没有中间包装器的情况下处理function*调用 other 。function*伴随函数有点棘手,因为它必须处理一堆生成器。

执行流程可能难以理解,因为yield/nextfunction*和同伴函数之间的关系很小。理解流程的一种方法是使用您选择的库编写一个示例,console.log在您的代码和库中添加语句,然后运行它。

于 2013-09-19T21:00:41.403 回答
4

如果【阻塞io函数】被调用生成器的函数执行,是异步执行的吗?我猜是因为否则会导致阻塞行为。

我不认为生成器执行异步任务处理。使用生成器,只有一件事同时执行——只是一个函数可以停止执行并将控制权传递给另一个函数。例如,

function iofunc1() {
  console.log('iofunc1');
}

function iofunc2() {
  console.log('iofunc2');
}

function* do_stuff() {
  yield iofunc1;
  yield iofunc2;
  console.log('goodbye');
}


var gen = do_stuff();
(gen.next().value)(); 
(gen.next().value)(); //This line won't begin execution until the function call on the previous line returns
gen.next(); //continue executing do_stuff

如果您阅读了一些关于 nodejs 生成器的文章:

  1. http://jlong​​ster.com/2012/10/05/javascript-yield.html
  2. http://jlong​​ster.com/A-Study-on-Solving-Callbacks-with-JavaScript-Generators
  3. http://jlong​​ster.com/A-Closer-Look-at-Generators-Without-Promises

...他们都使用额外的函数/库来添加异步执行。

于 2013-07-07T23:18:28.853 回答
2

1:用生成器编写“线性”异步代码,是否有必要有一个调用函数迭代生成器,执行产生的函数作为回调并将回调的结果返回到生成器?

是的。我们称之为“发射器”。

2:如果问题 1 的答案是肯定的,那么产生的函数究竟是如何执行的 - 异步?

在生成器内部,您生成一个数组,其中包含:函数及其参数。在控制调用者(启动器)中,您使用 fn.apply(..,callback) 调用异步,将调用置于“generator.next(data);” (恢复)在回调中。

async 函数是异步执行的,但生成器将在屈服点“暂停”,直到调用回调(然后执行“generator.next(data)”)

完整的工作库和示例: https ://github.com/luciotato/waitfor-es6

于 2013-11-24T01:14:55.200 回答