【问题标题】:How do ES6 generators assist with non-blocking code? [duplicate]ES6 生成器如何辅助非阻塞代码? [复制]
【发布时间】:2014-08-21 14:44:03
【问题描述】:

我已经在 Node 中试验 ES6 生成器有一段时间了,但仍有一个问题我不明白。

在常规回调节点中,从数据库中获取值并并行执行其他操作看起来像这样:

function executeBoth(){

  db.find("value", function(results){
    console.log(results);
  });

  doSomethingElse("else", function(data){
    console.log(data);
  });
}

这个例子完全是人为的,但是请注意,通过调用executeBoth()db.finddoSomethingElse,不要等待对方完成,Node 可以同时执行这两个操作,并且代码是非阻塞的.

这是一个尝试做同样事情的生成器示例:

function* executeBoth(){

  var results = yield db.find("value");
  console.log(results);

  var data = yield doSomethingElse("else");
  console.log(data);
}

我不明白上面的代码如何避免第一个函数阻塞第二个函数。从我读到的内容(以下来源),似乎整个生成器在到达 yield 关键字时暂停。这对于依赖于从特定 yield 返回的值的代码行来说是有意义的,但这是否也意味着 db.find 会阻止 doSomethingElse 执行?

似乎可以通过将每个 yielded 值和依赖于它们的以下代码包装在它们自己的单独生成器中来解决,然后从普通函数中调用这些生成器。然而,如果这是创建非阻塞代码的最有效方式,它将鼓励过度使用许多具有可能重复的专用代码的小型生成器函数。我是否正确理解了生成器的基本机制?如果是这样,解决方法是什么?提前致谢。

source onesource twosource three

【问题讨论】:

标签: javascript node.js generator coroutine ecmascript-harmony


【解决方案1】:

你是对的,在你的例子中,db.find 方法被执行,生成器等待直到该操作完成,然后它会继续直到它到达doSomethingElse

我将从generator library co 中窃取以下示例。 (你不需要使用它,你可以使用普通的生成器,但我喜欢它的语法和示例让它们为我“点击”)

假设在以下示例中,获取 Google 需要 10 秒,获取 Yahoo 需要 6 秒,而 cloudup 需要 5。

co(function *(){
  var a = yield get('http://google.com');
  var b = yield get('http://yahoo.com');
  var c = yield get('http://cloudup.com');
  console.log(a[0].statusCode);
  console.log(b[0].statusCode);
  console.log(c[0].statusCode);
})()

这会获取第一个站点,等待,然后获取第二个,等待,然后获取第三个。就像你的例子。它将在 10+6+5 = ~21 秒内完成。

co(function *(){
  var a = get('http://google.com');
  var b = get('http://yahoo.com');
  var c = get('http://cloudup.com');
  var res = yield [a, b, c];
  console.log(res);
})()

然而,这会有所不同:它开始获取第一个、第二个和第三个。返回值 (a,b,c) 要么是 promises,最终将报告它们已完成,要么是简单的回调。
yield 语句将等到所有三个 promise/callbacks 都被解决。以什么顺序无关紧要。它会在大约 10 秒内完成。

【讨论】:

  • 是的,产生一组 promise 或 thunk 更有效,但它仍然是阻塞的。如果对 cloudup.com 的 get 请求在对 yahoo.com 的请求完成前 4 秒完成会怎样?然后 cloudup.com 请求必须等到 yahoo.com 请求之后才记录,因为该 yield 会暂停所有执行,直到所有三个值都到达。
  • @user3181113:是的,这就是计划?当然,您也可以(至少通过承诺)也可以使用var a = get('http://google.com'), b = get('http://yahoo.com'), c = get('http://cloudup.com'); console.log(yield a); console.log(yield b); console.log(yield c);,这样如果a 在其他两个之前到达,则可以记录它。
  • 很好的解释,谢谢
猜你喜欢
  • 1970-01-01
  • 2014-12-24
  • 2015-11-25
  • 1970-01-01
  • 2013-11-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多