You Don't Know JS: Async & Performance by Kyle Simpson

You Don't Know JS: Async & Performance by Kyle Simpson

Author:Kyle Simpson [Simpson, Kyle]
Language: eng
Format: epub, azw3, pdf
Tags: js, o'reilly
ISBN: 9781491905203
Google: ir_ZoAEACAAJ
Amazon: 1491904224
Publisher: O'Reilly Media
Published: 2015-01-24T13:00:00+00:00


Generator Iterator

Let's turn our attention back to generators, in the context of iterators. A generator can be treated as a producer of values that we extract one at a time through an iterator interface's next() calls.

So, a generator itself is not technically an iterable, though it's very similar -- when you execute the generator, you get an iterator back:

function *foo(){ .. } var it = foo();

We can implement the something infinite number series producer from earlier with a generator, like this:

function *something() { var nextVal; while (true) { if (nextVal === undefined) { nextVal = 1; } else { nextVal = (3 * nextVal) + 6; } yield nextVal; } }

Note: A while..true loop would normally be a very bad thing to include in a real JS program, at least if it doesn't have a break or return in it, as it would likely run forever, synchronously, and block/lock-up the browser UI. However, in a generator, such a loop is generally totally OK if it has a yield in it, as the generator will pause at each iteration, yielding back to the main program and/or to the event loop queue. To put it glibly, "generators put the while..true back in JS programming!"

That's a fair bit cleaner and simpler, right? Because the generator pauses at each yield, the state (scope) of the function *something() is kept around, meaning there's no need for the closure boilerplate to preserve variable state across calls.

Not only is it simpler code -- we don't have to make our own iterator interface -- it actually is more reason-able code, because it more clearly expresses the intent. For example, the while..true loop tells us the generator is intended to run forever -- to keep generating values as long as we keep asking for them.

And now we can use our shiny new *something() generator with a for..of loop, and you'll see it works basically identically:

for (var v of something()) { console.log( v ); // don't let the loop run forever! if (v > 500) { break; } } // 1 9 33 105 321 969

But don't skip over for (var v of something()) ..! We didn't just reference something as a value like in earlier examples, but instead called the *something() generator to get its iterator for the for..of loop to use.

If you're paying close attention, two questions may arise from this interaction between the generator and the loop:

Why couldn't we say for (var v of something) ..? Because something here is a generator, which is not an iterable. We have to call something() to construct a producer for the for..of loop to iterate over.

The something() call produces an iterator, but the for..of loop wants an iterable, right? Yep. The generator's iterator also has a Symbol.iterator function on it, which basically does a return this, just like the something iterable we defined earlier. In other words, a generator's iterator is also an iterable!



Download



Copyright Disclaimer:
This site does not store any files on its server. We only index and link to content provided by other sites. Please contact the content providers to delete copyright contents if any and email us, we'll remove relevant links or contents immediately.