5

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

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

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

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

使用时是什么done样子yield的?

4

2 回答 2

3

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

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

只有在这种情况下co,那些异步回调的事情(和其他事情)才会“适当地”处理,因为您认为在异步控制流库中是自然的。

当使用 yield 时,done 是什么样子的?

您阅读的文章中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.val的结果gen.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
});
于 2014-05-08T23:37:14.970 回答
2

我在这里发布了关于生成器如何工作的详细说明。

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()

于 2014-05-08T23:34:26.727 回答