ES6 generators mechanism - first value passed to next() goes where?

Viewed 1190

When passing parameters to next() of ES6 generators, why is the first value ignored? More concretely, why does the output of this say x = 44 instead of x = 43:

function* foo() {
    let i = 0;
    var x = 1 + (yield "foo" + (++i));
    console.log(`x = ${x}`);
}

fooer = foo();

console.log(fooer.next(42));
console.log(fooer.next(43));

// output:
// { value: 'foo1', done: false }
// x = 44
// { value: undefined, done: true }

My mental model for the behavior of such a generator was something like:

  1. return foo1 and pause at yield (and the next call which returns foo1 takes as argument 42)
  2. pause until next call to next
  3. on next yield proceed to the line with var x = 1 + 42 because this was the argument previously received
  4. print x = 43
  5. just return a {done: true} from the last next, ignoring its argument (43) and stop.

Now, obviously, this is not what's happening. So... what am I getting wrong here?

4 Answers

Everything immediately became clear once I made this realization.

Here's your typical generator:

function* f() {
  let a = yield 1;
  // a === 200
  let b = yield 2;
  // b === 300
}

let gen = f();
gen.next(100) // === { value: 1, done: false }
gen.next(200) // === { value: 2, done: false }
gen.next(300) // === { value: undefined, done: true }

But here's what actually happens. The only way to make generator execute anything is to call next() on it. Therefore there needs to be a way for a generator to execute code that comes before the first yield.

function* f() {
  // All generators implicitly start with that line
  // v--------<---< 100
       = yield
  // ^-------- your first next call jumps right here

  let a = yield 1;
  // a === 200
  let b = yield 2;
  // b === 300
}
Related