function* foo() { yield 123 }; // - - - function* foo() { return yield 123 };
I can’t seem to demonstrate the difference between the two.
return
be used in a generator?Return simply returns the value after the function call, and it will not allow you to do anything else after the return statement. Yield works different. Yield returns a value only once, and the next time you call the same function it will move on to the next yield statement.
When you use a yield keyword inside a generator function, it returns a generator object instead of values. In fact, it stores all the returned values inside this generator object in a local state.
The yield keyword pauses generator function execution and the value of the expression following the yield keyword is returned to the generator's caller. It can be thought of as a generator-based version of the return keyword. yield can only be called directly from the generator function that contains it.
The yield * expression is used with generator functions or iterables. If the iterable is empty or the generator function has no yield keyword, the iterator returned from the main generator function call will be completed with the first call to next() and will never pause in between the yield * calls.
First, I'll start by saying that Generators are a somewhat complicated topic, so giving a complete overview here won't be possible. For more information I'd highly recommend Kyle Simpson's You Don't Know JS series. Book 5 (Async & Performance) has an excellent discussion on the ins and outs of generators.
Onto the specific example you gave though!
First, the code that you wrote in the example will show no difference but only if it's run correctly. Here's an example:
function* foo() { yield 123; } function* bar() { return yield 123; } var f = foo(); var b = bar(); f.next(); // {value: 123, done: false} f.next(); // {value: undefined, done: true} b.next(); // {value: 123, done: false} b.next(); // {value: undefined, done: true}
As you can see, I'm not calling the generator like a normal function. The generator itself returns a generator object (a form of iterator). We store that iterator in a variable and use the .next()
function to advance the iterator to the next step (a yield
or return
keyword).
The yield
keyword allows us to pass a value into the generator, and this is where your examples will run differently. Here's what that would look like:
function* foo() { yield 123; } function* bar() { return yield 123; } var f = foo(); var b = bar(); // Start the generator and advance to the first `yield` f.next(); // {value: 123, done: false} b.next(); // {value: 123, done: false} /** Now that I'm at a `yield` statement I can pass a value into the `yield` * keyword. There aren't any more `yield` statements in either function, * so .next() will look for a return statement or return undefined if one * doesn't exist. Like so: */ f.next(2); // {value: undefined, done: true} b.next(2); // {value: 2, done: true}
Notice that foo()
will return undefined
as a value, whereas bar()
returns the number 2. This is because the value we're passing into the .next()
call is sent to the return
keyword and set as the return value. foo()
has no explicit return statement, so you get the default undefined
behavior.
Hope that this helps!
The difference is the result value of the last continuation call:
function* fooA() { yield 123 }; var a = fooA(); console.log(a.next(1)); // {done:false, value:123} console.log(a.next(2)); // {done:true, value:undefined} function* fooB() { return 40 + (yield 123) }; var b = fooB(); console.log(b.next(1)); // {done:false, value:123} console.log(b.next(2)); // {done:true, value:42}
Most generators don't need a return
value, their purpose is the generation of a value stream as a side effect when they are running. All iterators are of this kind, if they are ran by a for of
loop the result just signifies the end, but the value is discarded.
However, there also are generators where a result value is important, e.g. when they are used as a tool to describe asynchronous processes (in a polyfill for async
/await
promise syntax, or also many more things like CSP). You also get the return
ed value when using yield*
on an iterable.
In any case, return yield
together doesn't sound very useful.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With