Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript function generators parameters

I am learning this feature from ES6(Function generators) and I am having difficulties to understand the following code :

function* HelloGen2() {
  var a = yield 100;
  var b = yield a + 100;

  console.log(b);
}

var gen2 = HelloGen2();

console.log(gen2.next());     // {value: 100, done: false}
console.log(gen2.next(500));  // {value: 600, done: false}
console.log(gen2.next(1000)); // {value: undefined, done: true}

Questions :

1 : In the first gen2.next() the line of code var a = yield 100; is called , is it set some value on the var a variable ?
2: In each gen2.next() only the line until the semicolon is executed ?
So for instance , in the second call gen2.next(500) the line console.log(b); is not executed
3: i do not understand the last line gen2.next(1000), how the b variable get the 1000 value ?

like image 705
tt0686 Avatar asked Jan 29 '23 11:01

tt0686


2 Answers

When working with coroutines, it's important to understand, that although yield and next are different keywords, what they do is essentially the same thing. Imagine two coroutines as being connected by a two-way communication pipe. Both

 Y = yield X

and

 Y = next(X)

perform the same set of operations:

  • write X to the pipe
  • wait for the answer
  • once the answer is there, read it from the pipe and assign it to Y
  • proceed with the execution

Initially, the main program is in the active state, and the generator (gen2 in your example) is waiting listening to the pipe. Now, when you call next, the main program writes a dummy value (null) to the pipe, thus waking up the generator. The generator executes yield 100, writes 100 to the pipe and waits. The main wakes up, reads 100 from the pipe, logs it and writes 500. The generator wakes up, reads 500 into a, etc. Here's the complete flow:

    gen                   wait

main next()               null -> pipe
main                      wait

    gen                   pipe -> null
    gen yield 100         100 -> pipe
    gen                   wait

main                      pipe -> arg (100)
console.log(arg)          100
main next(500)            500 -> pipe
main                      wait

    gen a=                pipe -> a (500)
    gen yield a + 100     600 -> pipe
    gen                   wait

main                      pipe -> arg (600)
console.log(arg)          600
main next(1000)           pipe -> 1000
main                      wait

    gen b=                pipe -> b
    console.log(b)        1000
    gen (ended)           done -> pipe

main                      pipe -> arg (done)
console.log(arg)
main (ended)

Essentially, to understand generators, you have to remember that when you assign or somehow else use the result of yield/next, there's a pause between the right and the left (or "generate" and "use") parts. When you do

  var a = 5

this is executed immediately, while

 var a = yield 5

involves a pause between = and yield. This requires some mental gymnastics, very similar to async workflows, but with time you'll get used to that.

like image 96
georg Avatar answered Jan 31 '23 08:01

georg


The relationship between yield x and generator.next(y) is as follows:

  • generator.next(y) returns {value: x, done: false}
  • yield x evaluates to y

Additionally, a generator function doesn't begin execution when initially invoked. You can think of it as a constructor. Only after generator.next() is called does the actual function code execute until the first yield statement (or the function terminates).

In your example:

  • var gen2 = HelloGen2() creates the generator, but nothing happnes.
  • gen2.next() executes the function up to yield 100 and then returns {value: 100...}.
  • gen2.next(500) resumes function execution, firstly evaluating the yield statement to 500 (and immediately setting this value into a), and continue execution up to yield a+100 and then returns {value: 600...}.
  • gen2.next(1000) resumes function execution, firstly evaluating the yield statement to 1000 (and immediately setting this value into b), and continue execution up to termination and then returns {value: undefined, done: true}.

That last undefined is the result of the function not returning any value explicitly.

like image 42
Amit Avatar answered Jan 31 '23 09:01

Amit