Search code examples
javascriptecmascript-6iteratorgeneratoryield

yield statment behaviour in a generator function


Learning about generators I've got this example from MDN :

function* fibonacci() {
  var fn1 = 0;
  var fn2 = 1;
  while (true) {  
    var current = fn1;
    fn1 = fn2;
    fn2 = current + fn1;
    var reset = yield current;
    if (reset) {
        fn1 = 0;
        fn2 = 1;
    }
  }
}

var sequence = fibonacci();
console.log(sequence.next().value);     // 0
console.log(sequence.next().value);     // 1
console.log(sequence.next().value);     // 1
console.log(sequence.next().value);     // 2
console.log(sequence.next().value);     // 3
console.log(sequence.next().value);     // 5
console.log(sequence.next().value);     // 8
console.log(sequence.next(true).value); // 0
console.log(sequence.next().value);     // 1
console.log(sequence.next().value);     // 1
console.log(sequence.next().value);     // 2

I appreciate an elaborate text to answer the following questions together :
Why is reset tested falsy after all those yield current assigned to it? that leads to a more general question: How does yield behave in assignment?
Where exactly does a value passed to next() go? because here in this code

function *createIterator() {
 let first = yield 1;
 let second = yield first + 2; // 4 + 2
 yield second + 3; // 5 + 3
}
let iterator = createIterator();
console.log(iterator.next()); // "{ value: 1, done: false }"
console.log(iterator.next(4)); // "{ value: 6, done: false }"
console.log(iterator.next(5)); // "{ value: 8, done: false }"
console.log(iterator.next()); // "{ value: undefined, done: true }"   

now I replace yield first + 2 by yield (first + 2) and still got the same results. So what is the mechanics behind that?

A step by step detailed answer would be golden since I'm new to this programming style. I repeat for the speed readers: please help me understand how Javascipt execute such code instruction by instruction, thanks


Solution

  • When yields is assigned it has two uses:

    The first is its primary use:

    It determine each object returned by the next() method of the iterator.

    The second is when assigned:

    The trickiest part to understand is that the primary role of yield is performed here first (the right part of an assignment). then the generator code freezes. The next time next() is called it resumes its execution. With first assigning the current next() argument to the left part of the assignment.

    Knowing that and that:

    Each time the generator's next() method is called, the generator resumes execution and runs until it reaches one of the following:

    A yield, which causes the generator to once again pause and return the generator's new value. The next time next() is called, execution resumes with the statement immediately after the yield. ...

    Here's what execution of the second example looks like :

    iterator.next()--->>>
    yields 1
    //next returns 1 in the 'value' property
    //Freezing until the next call to next
    iterator.next(4)--->>>
    let first =4
    yield first + 2;
    //next returns 6 in the 'value' property
    //Freezing until the next call to next 
    iterator.next(5)--->>>
    let second = 5
    yield second + 3;
    // That is 8 in the value property
    

    useful links :