ES6生成器如何协助非阻塞代码?

时间:2014-07-01 06:11:08

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

我现在已经在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执行吗?

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

source onesource twosource three

1 个答案:

答案 0 :(得分:2)

你是对的,在你的例子中,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语句将一直等到所有三个promises / callbacks都被解决。它的顺序无关紧要。它将在~10秒内完成。