2014-07-01 23 views
3

我一直在使用Node中的ES6生成器进行一段时间的实验,还有一个问题我不明白。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

+0

你可能想看看[了解带有yield/generators的代码流](http:// stackoverflow。com/q/23551418/1048572) – Bergi

回答

2

你说的没错,在你的榜样,执行db.find方法,发电机等到该操作完成后,然后它会继续,直到它击中doSomethingElse

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

假设在下面的示例中,获取Google需要10秒钟,取雅虎需要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)或者是承诺最终将报告它们已完成或简单回调。
yield语句将等待所有三个promise /回调都解决。以什么顺序排列并不重要。它会在10秒内完成。

+0

是的,产生一组promise或thunks效率更高,但仍然阻塞。如果在向yahoo.com的请求完成之前4秒内完成对cloudup.com的获取请求,该怎么办?然后,cloudup.com请求必须等到yahoo.com请求之后再进行记录,因为该收益会暂停所有执行,直到所有三个值都到达。 – user3181113

+0

@ 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'可以被记录,如果它在另外两个之前到达。 – Bergi

+0

很好的解释,谢谢 – mrcrgl