Generators and return
The
yield
statement by itself doesn’t end a generator, even if it’s the last statement in
the generator. Calling
return
from anywhere in the generator will result in
done
being
true
, with the
value
property being whatever you returned. For example:
function*
abc
() {
yield
'a'
;
yield
'b'
;
return
'c'
;
}
const
it
=
count
();
it
.
next
();
// { value: 'a', done: false }
it
.
next
();
// { value: 'b', done: false }
it
.
next
();
// { value: 'c', done: true }
While this is correct behavior, keep in mind that things that use generators don’t
always pay attention to the
value
property when
done
is
true
. For example, if we use
this in a
for...of
loop, “c” won’t be printed out at all:
// will print out "a" and "b", but not "c"
for
(
let
l
of
abc
()) {
console
.
log
(
l
);
}
I recommend that you do not use return to provide a meaningful
value in a generator. If you expect a useful value out of a generator,
you should use yield; return should only be used to stop the gen‐
erator early. For this reason, I generally recommend not providing
a value at all when you call return from a generator.
Conclusion
Iterators provide a standard mechanism for collections or objects that can provide
multiple values. While iterators don’t provide anything that wasn’t possible prior to
ES6, they do standardize an important and common activity.
Generators allow functions that are much more controllable and customizable: no
longer is the caller limited to providing data up front, waiting for the function to
return, and then receiving the result of the function. Generators essentially allow
computation to be deferred, and performed only as necessary. We will see in
how they provide powerful patterns for managing asynchronous execution.
182 | Chapter 12: Iterators and Generators