JS.Next: ES6 / ES2015 Generators
This course has been updated! We now recommend you take the ES6: The Right Parts course.
Transcript from the "Generators" Lesson
>> Aaron Frost: Okay, what do generators solve? Let's talk about it real quick. So consider this code here. So, we're going to say, set timeout and after one millisecond go ahead and log this, just wait a millisecond and log it, right? Is it going to wait a millisecond? It might wait as little as a millisecond, but there's no guarantee it's going to fire in a millisecond, at all.
[00:00:31] It will at least wait a millisecond, though. That's the only thing you know for sure is it will not fire in less than a millisecond. That's all you know for a fact. So, then we have this foo function that we're going to call right here. And we're going to say, wall I is less than 1E10, which is a gigantic number.
[00:00:52] Go ahead and just start logging stuff for the console. It's going to be awesome, just go ahead and log it all out. So, how long is this going to run for? When we call foo, how long is going to take to execute? Anyone know?
>> Aaron Frost: A long time, probably, right?
>> Speaker 2: Longer than one millisecond.
>> Aaron Frost: Way longer than one millisecond, right?
>> Speaker 2: [LAUGH]
>> Aaron Frost: So when you run this code, this is actually going to print out in this order. It's actually going to log all this stuff, and it's going to block for however long it needs, and then it will return control back to the timeout, so the timeout can do what it wanted to do.
[00:01:33] So when you say setTimeout, basically all you're saying is you're up next. Like, no guarantees when you're up, but whenever that is, you're up next, okay. So this is kind of a problem, and this is this is partly why generators came around to help. So, what if you could pause that and restart it, though?
[00:01:55] Like if you could say, dude, why don't you take a break off for a second? As soon as you said pause, the setTimeout would go, I've been waiting for like five milliseconds, what took you so long? And then it would run and then maybe you could resume again at that point.
[00:02:09] If you could pause, stop blocking the flow, and then let everything through and then take back over when you're done, that might help the flow, might make performance look a little bit better. If you could though, those two things would switch places, right? The wait millisecond would finish before that, the four one, because that wouldn't block the process any more, okay.
[00:02:51] I'm switching the star back and forth. Apparently either one is cool. I'm just putting it on the function, in the name of it, because it seems to make more sense to me like that. And then, the other new syntax you gain is this yield guy, okay? So, we've picked up this star symbol, along with our name, and then you've picked up yield as well, which is a thing we haven't had before.
[00:03:18] And yield is going to take a second to understand, so let me show you how it's going to work.
>> Aaron Frost: Besides yield, this body of this code in this generator is just a regular method body, with the exception of the word yield. So let me show you how you use it.
>> Aaron Frost: So if I call this geni, it's actually not going to execute my code. Okay, it just returned to me this generator iterator, okay? That's all it did. So in order to execute it, I actually have to call geni.next. And then geni.next is going to start the execution.
[00:04:02] Okay, and the first time I called next, it ran to this yield. Okay, and what it yielded, yield is kind of like return, but it's more like pause and send this value back. Okay, that's more what yield stands for. So when it yielded, it went ahead and it yielded this one back to me, okay?
[00:04:20] So I now, it gave me back this thing that said value is one and done is false, I'm still not done. Okay, so then I'm going to call it again. Yes, anyways, treat yield like return. So notice that when I called it a second time, it yielded me this 2.
[00:04:41] It said go ahead and return this 2 but pause, done's still false. And then the third time, go ahead and return the 3, so it didn't yield anymore. So my generator is kind of done at this point. It's like there's no more yields, you actually called return, so I'm done, I'm breaking out of this generator code.
[00:05:02] Okay, so if I call next one more time, it just is going to return an undefined value. It's going to say, yeah, you're done. There's nothing coming out of this generator, it's not generating anymore. Okay so, if we call this, it's going to go ahead and it's going to log 1,2,3,4,5 but not 6.
[00:05:24] Okay, because when you call foo what does foo give you back? Do you guys remember the terminology? A generator iterator. So when you call the generator function, it gives you back a generator iterator. I wish there was a better name, but there's not. So, it gives you, and then it's for of syntax, you guys remember the for of syntax?
[00:05:46] It will take anything that's got an iterable on it and it will iterate through it, okay? Well the iterator only returns something if done is not equal to true. So, when it returned this, done was true. That's why 6 didn't get logged, because done was true. So it's kind of like a no op on that thing.
[00:06:08] That make sense? Okay, we're going to take it to the next level real quick.
>> Speaker 3: Sorry, one more thing. So you cannot have a return value in a generator function?
>> Aaron Frost: Yes, at the end. As soon as you call return, your generator function, you've got to get a new one, your generator is dead.
[00:06:28] Like not dead, but it's done.
>> Speaker 3: But I mean, if I would like to get the 6 out, what should I do?
>> Aaron Frost: You would yield the 6.
>> Speaker 3: Okay, yes, on the return, but then basically the return value of the return gets ignored.
>> Aaron Frost: Yes, and then on the next line you can say return undefined, I don't care, yes.
[00:06:46] Or just return semicolon, so yes. So yes, the for loops only continue on an iterator while done is false. So that's why 6 didn't get logged, okay, so-
>> Speaker 4: Quick question on it, can you do a plus one to get the return? In the for loop, I think?
>> Aaron Frost: Plus one? Where?
>> Speaker 4: Yes, so I guess-
>> Aaron Frost: I don't even know what that means.
>> Speaker 4: Yes, I don't know where you would put it, but yes.
>> Aaron Frost: Yes. I'm going to say I don't know what that means. If you, Tony, if you figure it out let me know, if you know what you asked.
[00:07:25] Okay, so now we've gotten data out of a generator, so I've showed you guys how to make it yield things back to you. Now let me show you how to get things into it. Okay, this function is super exciting. Okay, don't kill me for it, is an example.
[00:07:41] I'm just trying to show you how you can control some flow with these generators. Okay, so I made a generator and I passed it 5, I called next, it returned to me 6. I called next passing it 12, it gave me 8, I called next passing it 13, it gave me 32, and so and so.
[00:08:00] Let me walk you through what happened here, because this code right here, doesn't make a lot of sense unless you understand what yield is doing. So I'm trying to explain what yield is doing, okay? Everyone's got to focus though, because it takes a second. I mean I know it's the end of the day, but like seriously, bloody like focus on it.
[00:08:23] Okay, so we called foo and we passed it 5, agreed? That means that x is equal to 5, our incoming parameter is 5. We cool so far? Okay, but remember when we called foo it didn't actually execute any code, all it did was set the parameter to 5 and returned me a generator iterator.
[00:08:44] We agree? Okay, so now I called genit.next and it went ahead and it executed that code that's in blue. It went ahead and yielded x plus 1. Okay, so what's x plus 1? Who remembers what x is? X is five. So it yielded x plus one, so it yielded 6.
[00:09:10] So we got value 6, done false. Okay so, all right, good so far. Okay, now we're going to do our next one. So now we called next, and passed it 12, you guys agree? So when we passed it 12, it went ahead and put the 12 in the space of where our code was, okay?
[00:09:35] So that's how I get values into it. So I said, go ahead and call .next and pass 12 in. So what is y going to equal?
>> Aaron Frost: Y is equal to 2 times anything in these parentheses. So what does it equal?
>> Speaker 2: 24.
>> Aaron Frost: 24, right? So y is equal to 24.
[00:09:54] Okay, and then it's going to keep going.
>> Aaron Frost: So it's going to go ahead and yield back to me y divided by 23. What's y divided by 23, or sorry, what's y divided by 3? You guys know, I know you know.
>> Aaron Frost: I can has math. Yes, it's 8.
[00:10:20] So it's going to go ahead and yield 8 back to me, okay, and the done is still false. So then, I'm going to go ahead and I'm going to call next again, passing it 13. Which is going to set z equal to 13, and then it's going to go ahead and yield back to me 5 + 24 +13, which is equal to 42.
[00:10:43] You can see it, it's in the slide and the done is true now. My gosh, did everyone understand that? Tell me if I didn't have my blue highlights you would have got it.
>> Speaker 2: [LAUGH]
>> Aaron Frost: It took me a while to get the highlights in there, but it's the only way I could conceptualize it so I figured it would make sense.
[00:11:05] So that kind of makes sense how generators work. And again, Kyle Simpson, he's got a bunch of generator stuff, in one of the other Frontend Masters courses, so if you really want to dive into generators, check out his course. Okay.
>> Speaker 2: Is there a practical application of actually setting up a generator like that?
>> Aaron Frost: Yes, check out Kyle's stuff. Mark says he's a genius on how it can be really, really cool to fit the way we think.
>> Speaker 5: Yes, I mean his basic case is that humans kind of think synchronously, logic and reason about code synchronously. And if you are coding with generators, and he has some different patterns and whatever, you can write synchronous code, but are doing asynchronous routines.
>> Aaron Frost: Check it out.
>> Speaker 3: And it's great for Fibonacci.
>> Aaron Frost: Yes, it's great for Fibonacci. Godwin's Law, we just did Godwin's Law again. Okay so it has a companion feature called Generator Expressions, and those got pushed to ES7. So they're not going to be in. So if you heard about them and you're like dude, Generator Expressions, they're out.