Transcript from the "Challenge 10: Autocomplete, Part 4" Lesson
>> Mike North: The fourth step of autocomplete. So we have a new file that has entered the picture here. The autocomplete file is still there from the last one that we just worked on, what's been added is a new file called the task.ts. It takes a generator function as an argument.
[00:00:18] And then the job of this task.js is to allow the yield within the generator function that is passed to this task thing to behave exactly as await would in an async function. Tasks should return a promise that resolves to the last value yielded or the value returned by the generator function.
[00:00:41] So let me show you how things have slightly changed in the autocomplete file. I've kind of lead us right up to an interesting point here.
>> Mike North: So if we say,
>> Mike North: Diff exercises autocomplete 4,
>> Mike North: Diffing the one we have now against the previous one.
>> Mike North: It's not gonna show me a nice inline diff.
[00:01:28] Can I do this?
>> Mike North: Nope,
>> Mike North: Well, okay, we'll just do it this way.
>> Mike North: I assumed that that would work, and now it's not, so well. We'll just toggle. So this is the one we were just working with. Scroll all the way to the top, scrolled all the way to the top.
[00:02:03] And we'll compress this. So we've got await fetchPlaceSumaries, await fetchPlaceDetials. What has changed here, and note it's an async function. In this exercise we're doing right now, it is an async function that returns a generator function that has passed into this task thing, which is our job to define.
[00:02:30] So we don't have awaits here, we have yields, we have yields. Now, this still pauses execution, we've seen how yield works. We've seen that as we pull things off of an iterator, we get a value, and then we can push something into the next function onto the iterator, and that will completely assignment here.
[00:02:50] So at its core, what we're gonna do is in this task function, we're going to be passed a generator function. This is your generator function that you're gonna get. You're gonna grab an iterator, and what you're gonna pull off of this iterator when you call iterator.next, you're going to get what type?
>> Speaker 2: Promise.
>> Mike North: A promise, you're gonna get a promise. When that promise resolves, you're gonna pull the next promise off the iterator and push the result of the previous one in to complete the assignment. So I just wanna direct you back to this exercise we looked at here, sorry, right here, this one.
[00:03:36] So remember this iterator. This would be, if instead of numbers, let's imagine that these are promises that we're yielding out, right? So we get the number 5, but imagine that's a promise. And instead of in the next line of code, calling it.next, imagine we waited for that promise to first resolve.
[00:03:57] Once it resolves, we have the value that that promise resolves to. And instead of pushing 35 in, we can push in that resolved value. And that is going to complete this assignment operation, right? So on the left side of yield, whatever that is, now we can write that almost as synchronous code.
[00:04:14] We can say yield a promise, and when we come back and resume execution, I will have whatever you resolve to, right? So you're gonna do this over and over again, and walk through the whole promise chain, until your iterator indicates that you're done. And just remember whatever the last result is that you yielded, and basically, this will create something that is exactly like async await.
[00:04:38] It'll work just the same way.
>> Speaker 3: It'll be like chained, right?
>> Mike North: What will be chained?
>> Speaker 3: The awaits?
>> Mike North: The awaits, so awaits, the behavior we're describing here, await makes this work right out of the box. But I just want you to note if we look at it side by side, let me get rid of this temporarily.
[00:05:04] If we look at autocomplete from the last exercise on the left and from this exercise on the right, note that they're very, let me delete the excess type annotations like I did before, just to line it up really nicely. This is pretty lined up here. So note we've got fetchPlaceSummaries on this line here, right?
[00:05:29] Both sides, fetchPlaceSummaries, the only difference is we have a yield, and then it's the same log and then the next is the map operation and then a yield. So the body of this generator function allows up to use a yield in the exact same way that we were able to use await in the last exercise.
[00:05:49] And that's what let us write something that under the hood is really a promise chain as if it's synchronous code. So we're gonna use this, we're gonna build this task function, which is, it's gonna operate this iterator in such a way that what we're looking at here kinda just works.
[00:06:06] And I'll tell you, it's not that complicated, you just have to take it step by step, start by grabbing promises and waiting for them to resolve. And sort of iterate through the promises and sequence and just pluck a new thing off the iterator each time. And then worry about passing the resolved values back in.
[00:06:24] And the solution's about 20 lines of code or even less, if you're clever, right? So this is not all that involved. But when you do this, you really understand in depth how generator functions and, how async and await, and how async functions are all kind of connected to this idea of pausing local execution context, picking back up where you left off.
[00:06:49] And you will understand this at a deeper level than most people end up reaching. So let's take a full 30 minutes for this one, and in particular, this is a great for this task.js file. It's a great one to sort of play around, use your code runner and write your own little thing down here.
[00:07:12] It might be that the way the autocomplete is using this task function does not serve you well until you're mostly finished. So you could just write your own thing down here like task, function, and I'll leave this on the screen, don't worry. We can say like yield. I actually gave you a little helper here.
>> Mike North: That's actually in this one, in the same module. So all wait does, it's a promise around a set timeout. So you could say yield wait(300) milliseconds, then console.log. And you should see these things are done in order, you're not just plowing straight through and setting all of your set timeouts in parallel.
[00:08:03] They're going in sequence, one, two, three, with a proper, you should be able to witness the promise chaining. So if you were to save this and run it, you should be able to see,
>> Mike North: [SOUND] Let's see, that's the task, this is not running.
>> Mike North: Of course, it is not implemented yet.
[00:08:25] But you should be able to use this to drive your code. And I would recommend start here with something simple, just using this wait helper to sort of pause and write something out. Anything that returns a promise is fair game to yield. And that'll help you get some intermediate steps before you try to just plug it in as an async await solution.
[00:08:45] Cuz you have to be kind of mostly done for that to give you signals that you're working out. So half hour, and we will go through the solution then. And I will then take it the next logical step forward where we will address some of the issues you brought up with each new key stroke canceling any pending things that might be coming in.
[00:09:07] So see you in a half hour.
>> Speaker 3: So with this solution, it won't cancel it, but the end state will still be correct?
>> Mike North: By the time we're done with this solution, it should work exactly as the end of the previous solution. We will have just implemented our own async and await as an exercise.
[00:09:30] And it will open the door for us to potentially cancel it in the near future.