3

I was reading this article about javascript generators, and I reached the following snippet:

function *foo(x) {
    var y = 2 * (yield (x + 1));
    var z = yield (y / 3);
    return (x + y + z);
}

var it = foo( 5 );

// note: not sending anything into `next()` here
console.log( it.next() );       // { value:6, done:false }
console.log( it.next( 12 ) );   // { value:8, done:false }
console.log( it.next( 13 ) );   // { value:42, done:true }

I don't understand the purpose of the first it.next(). After executing it, this line, shouldn't the iterator be paused at var z = yield (y / 3), with y having the value of 6? Shouldn't it.next(12) supply the param for yield (y / 3), and z be 4 after this? I don't understand why the result of the function is not 5 + 12 + 4. It's somehow as if the first it.next() is ignored. Is this the case? Can someone please shed some light?

j08691
  • 204,283
  • 31
  • 260
  • 272
Geo
  • 93,257
  • 117
  • 344
  • 520

2 Answers2

4

This may help

function *foo(x) {
    var y = 2 * (yield (x + 1)); 
       // x = 5 (from foo(5) ) so it yields 6
       // next(12) => var y = 2 * (12) == 24
    var z = yield (y / 3);
       // from above y = 24 so yields 8
       // next(13) => var z = 13    
    return (x + y + z);
       // 5 + 24 + 13 == 42 (and done: true)
}
Wainage
  • 4,892
  • 3
  • 12
  • 22
3

You might want to add some logging statements to see what is going on:

function *foo(x) {
    console.log("starting");
    var y = 2 * (yield (x + 1));
    console.log("y", y);
    var z = yield (y / 3);
    console.log("z", z);
    return (x + y + z);
}

var it = foo( 5 );
console.log("it", it);
console.log(it.next());
console.log(it.next(12));
console.log(it.next(13));

logs

it {next: …}
starting
{ value:6, done:false }
y 24
{ value:8, done:false }
z 13
{ value:42, done:true }

As you can see, calling foo(5) only creates the generator object, but does not yet start it. Only the first call to it.next() will do that, returning the result from the first yield. This first call does not take any argument, because it's not accessible inside the generator function anyway.

Only the second call to .next(12), here passing in a value, will then resume the generator code, with that passed-in value being the result of the yield expression (which is then multiplied by 2).

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Have I understood this correctly? Basically, after calling the first `it.next()`, 6 is returned to the caller, and node is suspending the function at that same yield? Thus, when calling `it.next(12)` it uses 12, instead of x+1, right? – Geo Mar 30 '16 at 17:51
  • @Geo: Exactly that is how `yield` works, yes :-) In most cases (like iterators) you don't care about the values that are passed in (or no values are passed at all), but you can do some fancy things with this. Go read on the article series you've linked in your question! – Bergi Mar 30 '16 at 17:55