了解产量/生成器的代码流

时间:2014-05-08 20:00:28

标签: javascript node.js generator yield co

我已经使用JavaScript生成器such as this one阅读了几个代码示例。我能提出的最简单的生成器使用块是:

function read(path) {
    return function (done) {
        fs.readFile(path, "file", done);
    }
}

co(function *() {
    console.log( yield read("file") );
})();

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

使用doneyield看起来像什么?

2 个答案:

答案 0 :(得分:3)

  

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

不,yield不是语法糖。它是生成器的核心语法元素。实例化该生成器后,您可以运行它(通过调用它上面的.next()),这将返回return ed或yield ed的值。当生成器yield时,您可以稍后再次调用.next()继续它。 next的参数将是yield表达式在生成器内返回的值。

co的情况下

,处理这些异步回调事物(和other things)"恰当"对于你在异步控制流程库中认为自然的东西。

  

使用产量时的效果如何?

article that you read中的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确实在运行时从生成器中生成表达式read("file")的值。这变为ret.valgen.next()的结果。为此,传递了next函数 - 一个回调函数,它将继续生成具有传递给它的res ult的生成器。在您的生成器代码中,看起来好像yield表达式返回了此值。

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

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
});

答案 1 :(得分:2)

我发布了有关生成器如何工作here的详细说明。

以简化形式,您的代码可能看起来没有co(未经测试):

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()异步迭代生成器对象。