ES6 (ES2015) - Generators

John Lindquist
InstructorJohn Lindquist
Share this video with your friends

Social Share Links

Send Tweet
Published 10 years ago
Updated 6 years ago

Generators in ECMAscript 6 are first-class coroutines that produce encapsulated suspended execution contexts. Whew! Yield values and iterate over them until no more values exist in the generator. We'll talk more about practical use later ;)

You make a generator by adding asterisks right here after the function keyword. I'll go ahead and add a log statement saying that you called next. You might think that if I called greet that it would log out you called next but nothing happens.

If we assign something like a greeter to this greet and then we see what the greeter is you can see that the greeter is actually an object so it did not invoke this. It actually created an object which I can call next(on). When I call greeter.next, and I'll just call this next and log that out. You can see that next is undefined and done true.

You can also see that it finally invoked our log statement saying that you called next. Now, this is undefined because we didn't yield anything from our generator. It's done because it's gone through all of the yield statements which are actually none right now.

If I yield a simple hello and run this again you can see now I get value hello and done false. It logged out our statement. It returned hello and it's not done yet. It will actually be done on the next pass through next.

If I call next again, and I'll just name this one done, and I call the log statement again, so I'll just log out done. You can see that I get hello on the first pass with done as false and undefined with done as true because there are no more yield statements after this one, meaning it had iterated and gone through all of the yield statements.

If you have multiple yield statements like how, are, and you and you run this with only calling next once you can see that it stops after calling how. This is not called. That's not called, and that's not called.

If you were to create any objects or anything inside of here they would not be created until you called next, meaning that you can put stuff in here that's not created until you explicitly need it.

If we go ahead and call next three more times and run it again you can see it logs out each log statement, then the yield, the log, then the yield. It logs this, then yields that, then logs this, then yields the next one.

Because it's an iterator you can also use the for/of syntax. We can say for word of greeter and then log out the word and then run that. You can see the output is basically the same. "How are you?" The main difference is that this is grabbing the value off of the next.

To do that by calling next we'd have to revert this and say .value, then run it again and we get the same output.

It's really easy to get mixed up when you start assigning things to yield statements. If I say let friendly equal yield how and then I try to log out friendly you might expect it to log out how because that's what it's yielding. But if I run this you'll see it's actually logging out undefined.

The way that this works is that the next step through the iteration, so if I say "The heck," will basically send this back through and assign it to this friendly. If I log this out now you'll see I get "How," and then "The heck." That means you can start building things through the iteration process.

If I yield friendly+r and then I assign friendly to this and then I yield friendly+u and I pass in silly ole and I run this again you can get "How the heck are silly ole you?" because this message is being returned here when the next step is run and assigned to this friendly. I yield that part of the friendly and then this comes from here, which is being assigned here. Then it yields that final statement.

One thing to note is that because this assignment happens on the run after the first one it's actually impossible to pass a value in here. If I try and say first and run this I'll get an error saying, "Sent value to a newborn generator," because you haven't given this a chance to run and iterate and go to the next step where you could actually pass in a value.

Lastly, generators also help you work with infinite sequences. If I wrap my yield with a wild true, which is never going to stop looking, I can safely yield this X and Y point knowing confidently that this stuff isn't going to evaluate until the next step through after the yield process.

It will safely pause instead of infinitely going through this while loop. When I run this, you can see I get zero, two, four, six, eight and so on. Zero, one, two, three, four, and so on. I could generate these forever. They're also only created when I request them through the yield. They're not created ahead of time.

Don't worry. We will dive more into practical use cases of generators in future videos.