通过yield / generator来理解代码stream

我已经阅读了几个使用JavaScript生成器的代码示例, 比如这个 。 我能想到的最简单的发电机组块就是这样的:

function read(path) { return function (done) { fs.readFile(path, "file", done); } } co(function *() { console.log( yield read("file") ); })(); 

这确实打印出file的内容,但是我的挂断是在done调用的地方。 看起来,yield是语法糖,用于包装它在callback中返回的内容,并适当地分配结果值(至less在co的情况下,将错误参数引发到callback函数中)。 我对语法的理解是否正确?

使用yield时的yield是什么?

       

网上收集的解决方案 "通过yield / generator来理解代码stream"

看起来,yield是句法糖,用于包装它在callback中返回的内容,并适当地分配结果值(至less在co的情况下,将错误参数抛出callback)

不, yield不是语法糖。 这是生成器的核心语法元素。 当这个生成器被实例化时,你可以运行它(通过调用.next() ),这将返回returnyield的值。 当发生器yield ,可以通过再次调用.next()继续。 接下来的参数将是yieldexpression式在生成器内返回的值。

只有co情况下,那些asynchronouscallback的东西(以及其他东西 )才会被“适当地”处理,以便在asynchronous控制stream库中认为是自然的东西。

使用收益率时的结果是什么?

您阅读的文章中的thread函数示例为您提供了一个很好的印象:

 function thread(fn) { var gen = fn(); function next(err, res) { var ret = gen.next(res); if (ret.done) return; ret.value(next); } next(); } 

在你的代码中, yield在运行时产生expression式read("file")的值。 这成为了ret.valgen.next()的结果。 为此,传递next函数 – 一个callback函数,它将继续传递给它的分辨率的生成器。 在您的生成器代码中,看起来好像yieldexpression式返回了这个值。

发生的事情的“展开”版本可以这样写:

 function fn*() { console.log( yield function (done) { fs.readFile("filepath", "file", done); } ); } var gen = fn(); var ret1 = gen.next(); var callasync = ret1.value; callasync(function next(err, res) { var ret2 = gen.next(res); // this now does log the value ret2.done; // true now }); 

我发布了发电机在这里工作的详细说明。

以简化forms,您的代码可能看起来像这样没有co (未经testing):

 function workAsync(fileName) { // async logic var worker = (function* () { function read(path) { return function (done) { fs.readFile(path, "file", done); } } console.log(yield read(fileName)); })(); // driver function nextStep(err, result) { try { var item = err? worker.throw(err): worker.next(result); if (item.done) return; item.value(nextStep); } catch(ex) { console.log(ex.message); return; } } // first step nextStep(); } workAsync("file"); 

workAsync的驱动程序部分通过调用nextStep()asynchronous地遍历生成器对象。