1

I am trying to understand how the heck this is working. I have manipulated this code inside out and still don't understand how it is returning the values it is. I got this from a tutorial at http://davidwalsh.name/es6-generators

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 seem to have somewhat of a grasp on the first next(), but the next 2 baffle me with the value of 8 and 42.

Hope someone can help explain this so I can try to grasp and move onto the next stages with the generators.

Jean-François Corbett
  • 37,420
  • 30
  • 139
  • 188
pertrai1
  • 4,146
  • 11
  • 46
  • 71
  • It seems like you are at least the second person to be baffled by this particular tutorial. Perhaps its time to find a different one. –  Nov 21 '14 at 07:03
  • Yes this is a duplicate, but I still don't think that the other question answered completely. Both answers say that the first value is 6, but the actual initial value for yield itself is 5. I think that it has to be understood the difference between what the execution context is before yield suspends and then when it pops the execution context and returns the evaluation. Is this not correct? – pertrai1 Nov 22 '14 at 08:04
  • I don't understand either part of your comment. What do you mean by "the actual initial value for yield itself is 5"? –  Nov 22 '14 at 08:21
  • if the 3rd next returns the value of 42, does not x need to be 5? If it is 6 then it does not add up to 42? – pertrai1 Nov 22 '14 at 14:54
  • `x` **is** 5. Nothing in the generator or iteration changes that. –  Nov 22 '14 at 17:32
  • Ok, so does that mean that the first time that the next() goes through it suspends and then does an evaluation before hitting the next yield? If that is the case then you have just made it to be complete sense for me on how the yield works. – pertrai1 Nov 23 '14 at 13:16
  • Thank you for hanging on with me on this. It now makes sense - more - on what happens during the process of messages going in and out. – pertrai1 Nov 24 '14 at 16:50

2 Answers2

5

Generators are not more than syntax sugar for closures, try this:

  function foo(x) 
  {
    var step = 0;
    var y;
    var z;

    function next(p) {

      switch( step++ ) {
        case 0: return { done:false, value:x + 1 }; break;
        case 1: y = 2 * p; return { done:false, value:y / 3 }; break;
        case 2: z = p; return { done:true, value: x + y + z }; break;
        default: return;
      }
    }
    return {next:next};
  }    

  var it = foo( 5 );
  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 }
c-smile
  • 26,734
  • 7
  • 59
  • 86
  • Ah! Thank you for sharing this. Another example that has helped shed light on this for me. Much appreciated. – pertrai1 Nov 21 '14 at 06:21
2

The argument to next becomes the value of the previous yield. This is the flow:

it.next() starts the generator. Its value is yielded as x + 1, which is 6.

it.next(12) resumes the generator, returning 12 as the value of yield (x + 1). y becomes 2 * 12, i.e. 24. The value of it.next(12) is yielded as 24 / 3, i.e. 8.

it.next(13) resumes the generator, returning 13 as the value of yield (y / 3), so 13 is assigned to z. The final result is thus 5 + 24 + 13, or 42.

TL;DR: next resumes the generator and passes value to be returned by yield. yield stops the generator and passes value to be returned by next. It's like this fun game of digital tennis.

Amadan
  • 191,408
  • 23
  • 240
  • 301
  • AWESOME!!! Thank you so much for making it simple to understand after I sat here in the console trying to figure it out. – pertrai1 Nov 21 '14 at 05:17