Check out a free preview of the full Rethinking Asynchronous JavaScript course
The "Messaging" Lesson is part of the full, Rethinking Asynchronous JavaScript course featured in this preview video. Here's what you'd learn in this lesson:
If the yield keyword in a generator is called with a value, that value will be returned to the iterator along with a “done” boolean value. This allows messages to be sent outside of the generator. Kyle explains why this is useful and also demonstrates that subsequent calls to the next() method can be used to pass message back into the generator.
Transcript from the "Messaging" Lesson
[00:00:00]
>> [MUSIC]
[00:00:03]
>> Kyle: This is going to feel strange and bizarre to those of you that haven't worked with generators before. So, just like everything else, what I'm suggesting to you is not in five minutes you're going to be an expert on this pattern. But I'm trying to suggest to you, if you trust me at all, trust me that this is where you should spend a whole bunch of time thinking, and practicing, and reading, because it's going to change everything that we do, with asynchronous programming.
[00:00:28]
I'm 100% convinced it's one of the most revolutionary changes to our language. That's why we spend time thinking about it. Okay. So, if we can pause a generator while it's running, it's also message passing. So here, I'm not just calling yield but I'm actually calling yield with a value.
[00:00:48]
In the previous case, when I showed no value in the yield expression, it was assumed that I was yielding undefined. But here I'm yielding actual values like 1, 2, and 3, and you notice that when I call yield 1, I return control back to line 9. By way of returning a value .next returns as an object.
[00:01:08]
That has two properties on it. It has a value property with the value that was yielded, if any. And it has a done property that tells us true or false is the generator complete. So that's where we get value: 1, done: false. And then we can call .next again right away or at some later time.
[00:01:28]
And we're gonna get value: 2, done: falls, and we want to call it again and yield 3. At that moment, it kind of looks to you visually like the generator is done, but it's not really done. That's why we still get done: false, because technically it's paused on that last expression.
[00:01:46]
Even though visually, we can look at the generator and say it's not going to do anything else, technically it's still paused. Technically, you can still do something with it. So that's why the fourth .next down there on line thirteen would resume the generator of the pause line four.
[00:02:03]
Immediately, there is nothing else to do. It would finish, it would complete. And then we would get an object back that there was no value given to us but there was a done: true. Now what about that value: undefined. Where do you suppose that comes from? Where it comes from is that in JavaScript, all functions that don't have a return statement imply a return undefined at the end.
[00:02:25]
So, there's an implied return undefined on line four and a half. Had we chosen to do a different return value, like for example, return four, we would have gotten value for done: true. On line 13. Does that make sense? So, at any point when you do a return from a generator, you immediately complete the generator, and whatever you've returned is sent out as the value.
[00:02:47]
But if you do a yield, the value is sent out and you get a done: false. Yeah?
>> Speaker 2: Can you iterate it, do a for each as a collection and get the value and stuff moving one .next at a time?
>> Kyle: I'm sorry, maybe ask the question-
>> Speaker 2: You're doing it.next, and you get the value.
[00:03:06]
Then you do an iterator .next, you get the next value?
>> Kyle: Yeah.
>> Speaker 2: Instead, can we loop through, like a four each loop, like a collection?
>> Kyle: Can you automatically run through a whole iterator? Absolutely, that's actually got nothing, not specifically about generators. It's any iterator. Can be run through a loop.
[00:03:24]
You could do your own four eye loop like that. You could be looking for the done: true thing, like a while loop looking for done: true. But there was a new looping style added to ES6, specifically for consuming iterators, and it's the four of loop. So, instead of four or four end, we now have a four of loop.
[00:03:46]
And if you give it an iterator, even one from a generator, if you give it an iterator, it will run the iterator to completion. And it automatically looks for the done: false and all that stuff. So, if you want to consume an iterator there is a looping syntax for it.
[00:04:00]
So, that's a very synchronous syntax which may or may not be what you want with the generator.
>> Kyle: All right, so this is clearly illustrating that messages can be passed out. But, it turns out that this is not only a one- way message passing, but actually they yield in the next pair together to create a two-way message passing system.
[00:04:24]
So, not only can we yield messages out, but when we call the next method we can pass a message in, and that message goes into the generator. I'm going to create a little helper for myself just to save space on the slides. Don't get too wrapped up in what this is, but it's wrapping around a generator.
[00:04:41]
You see on line 2, I'm executing my generator to produce an iterator. And then I'm returning a function that every time that function gets called, it's going to call the iterators.next pass in any arguments and return any value out. So, I'm just wrapping up the interator.next ,something that's a little cleaner and easier to illustrate with.
[00:05:00]
But any time you see the usage of this, you can just think it's just calling.next under the covers, okay?
>> Kyle: So this little helper. I'm gonna pass my generator to it, and what I get back is going to be a thing I call run. So, run is a function.
[00:05:15]
Every time I call run, it's calling the iterators next. So whenever you see run, this thing IT dot next. All right, so I haven't run anything in my generator on line 1, but I've simply set up this generator to be executed. And on line 7, I'm going to call the first run.
[00:05:33]
That's the first I teed up next call, and it's going to transfer control up to line 2. Now on line two, it's going to start to execute as a var X equals one plus and I see a yield expression. I cannot complete this statement at this moment. So, I'm literally going to pause the generator right in the middle of this statement, and wait for somebody to resume me, okay.
[00:05:58]
So, that yield keyword is going to return control to line seven. Now, that value that came back the IT dot next return value that we would see here would be an object that says, value undefined because we didn't yield anything, done: false. Is everybody with me? Value undefined, done: false.
[00:06:17]
Had we yielded something that would have been value whatever we yielded and still done: false.
>> Kyle: But here's where I want to tweak your brain a little bit, because this is all about perspective that helps you understand, gives you a path for understanding this. What I want you to do is, I want you to think about the perspective not from the outside world.
[00:06:37]
Because the outside world is how we typically would think about it. We think about driving this generator by our run calls. Want you to think about it from the inside perspective. From what's happening in the generator at the moment that I am online too ,and I encounter a yield keyword essential in this yield keyword is asking a question.
[00:06:56]
It is saying, I need some value here. It's like a placeholder that says, I need some value and I don't have it yet. I'm going to wait around until somebody gives me a value.
>> Kyle: Because I obviously need a value to finish the statement. Does everybody agree with that?
[00:07:12]
Okay. So, I'm simply going to pause waiting for a value, and I will tell you outside world that I've asked a question. I am asking for you to give me a value. At some later point like line 8, we're going to answer that question by sending a value back in.
[00:07:27]
And that value 10, will come in and will replace or complete that yield expression with that value. So, now the generator can resume and it can finish its work cuz it says, thank you for answering my question. The answer to my question was value ten. So, now I can add ten and one together and x is 11.
[00:07:48]
From the inside perspective, that's the key perspective you wanna have. Don't think so much about what's happening on the outside because the outside stuff is actually going to end up being buried away in some library. It's the inside stuff that matters. It's what's happening on the inside of the generator.
[00:08:04]
I'm asking a question. Now, here I asked a very simple question. I just said yield. I said give me some value. But what if my question was like making an AJAX call. And I said I need a response from an AJAX call. And I don't know how long it's going to take, but I'll just wait around until you give me a response.
[00:08:21]
So, we could have yielded an AJAX call. Okay. So, we've sent an answer back in by way of value ten. X is now 11, we go to line three. We start executing like one plus and then another yield keyword. So, we're asking another question, which means we're gonna pause and wait for that answer, and we're gonna return control back to line eight.
[00:08:43]
Line eight is gonna say, is gonna have an object value, undefined done: false. Just like line seven. At some later point, we're gonna answer that pending question by passing in the value 30 as we're doing on line ten. So that value 30 is going to come back and complete the yield expression that was waiting on line three.
[00:09:08]
Now, 30 can be added to one, and now y is 31. X was previously set to 11. And now, even though it's confusing with all these arrows, line four is going to yield out a value. You see, there is a value that I compute x plus y. It gets computed right away which is the value 42.
[00:09:27]
So, that's me asking the question with the value 42.
>> Kyle: So, I want to send out the value 42, and that's why I can say dot value, cuz I got an object that said value 42 done: false.
Learn Straight from the Experts Who Shape the Modern Web
- In-depth Courses
- Industry Leading Experts
- Learning Paths
- Live Interactive Workshops