最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Understanding code flow with yieldgenerators - Stack Overflow

programmeradmin0浏览0评论

I've read over several examples of code using JavaScript generators such as this one. The simplest generator-using block I can e up with is something like:

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

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

This does indeed print out the contents of file, but my hangup is where done is called. Seemingly, yield is syntactic sugar for wrapping what it returns to in a callback and assigning the result value appropriately (and at least in the case of co, throwing the error argument to the callback). Is my understanding of the syntax correct?

What does done look like when yield is used?

I've read over several examples of code using JavaScript generators such as this one. The simplest generator-using block I can e up with is something like:

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

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

This does indeed print out the contents of file, but my hangup is where done is called. Seemingly, yield is syntactic sugar for wrapping what it returns to in a callback and assigning the result value appropriately (and at least in the case of co, throwing the error argument to the callback). Is my understanding of the syntax correct?

What does done look like when yield is used?

Share Improve this question edited May 8, 2014 at 23:23 Bergi 667k161 gold badges1k silver badges1.5k bronze badges asked May 8, 2014 at 20:00 Explosion PillsExplosion Pills 192k55 gold badges340 silver badges416 bronze badges 1
  • Are you referring to done as used inside read(path)? I don't think it has anything to do with yield or generators specifically - it's part of the co library. – voithos Commented May 8, 2014 at 21:01
Add a ment  | 

2 Answers 2

Reset to default 4

Seemingly, yield is syntactic sugar for wrapping what it returns to in a callback and assigning the result value appropriately (and at least in the case of co, throwing the error argument to the callback)

No, yield is no syntactic sugar. It's the core syntax element of generators. When that generator is instantiated, you can run it (by calling .next() on it), and that will return the value that was returned or yielded. When the generator was yielded, you can continue it later by calling .next() again. The arguments to next will be the value that the yield expresion returns inside the generator.

Only in case of co, those async callback things (and other things) are handled "appropriately" for what you would consider natural in an async control flow library.

What does done look like when yield is used?

The thread function example from the article that you read gives you a good impression of this:

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

In your code, yield does yield the value of the expression read("file") from the generator when it is ran. This bees the ret.val, the result of gen.next(). To this, the next function is passed - a callback that will continue the generator with the result that was passed to it. In your generator code, it looks as if the yield expression returned this value.

An "unrolled" version of what happens could be written like this:

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

I posted a detailed explanation of how generators work here.

In a simplified form, your code might look like this without co (untested):

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

The driver part of workAsync asynchronously iterates through the generator object, by calling nextStep().

发布评论

评论列表(0)

  1. 暂无评论