Check out a free preview of the full Advanced Asynchronous JavaScript course
The "Challenge 1: Solution" Lesson is part of the full, Advanced Asynchronous JavaScript course featured in this preview video. Here's what you'd learn in this lesson:
Jafar walks through the solution and takes questions from students.
Transcript from the "Challenge 1: Solution" Lesson
[00:00:00]
>> Jafar Husain: Just as a little bit of help, I threw up our much simpler definition. Not too much simpler, a little bit simpler definition for array here of map, just to remind us all about how map works on an array. So lets see if we can extrapolate this understanding of how map works on an array, and implement map for observable.
[00:00:17]
It's a little bit trickier cuz there's a little more going on, but it's the same basic idea. We want to take all the items in the observable, apply a function to them, and then take their result and pump it into our observer. So we're gonna create a new observable that pulls all the items out of a source observable, runs them through a function, and then pumps the result into that new observable's observer.
[00:00:40]
So how do we get data out of the this observable? How do we get data out of any observable?
>> Speaker 2: Subscribe
>> Jafar Husain: Subscribe, yeah.
>> Jafar Husain: And what's gonna happen when we get a value from the input observable? What are we gonna do with it?
>> Speaker 2: Call next on the observer?
[00:01:04]
>> Jafar Husain: Yeah, call next on the observer, right.
>> Speaker 2: And project the value.
>> Jafar Husain: Right, we don't wanna just take the value and then send it to the observer, cuz the we haven't really done anything. We might as well not do a thing, right? First we wanna run it through our projection function.
[00:01:24]
>> Jafar Husain: Great, that's all there is to it, or is it? Have we forgotten anything?
>> Speaker 2: On subscribing?
>> Jafar Husain: On subscribing, sorry?
>> Speaker 2: Unsubscribing.
>> Jafar Husain: Unsubscribing, absolutely, right. We need to create an unsubcription.
>> Jafar Husain: So just like before,
>> Jafar Husain: So how are we gonna unsubscribe from this source observable?
[00:01:51]
>> Speaker 2: Do we use the unsubscribe that's taken from the first subscription?
>> Jafar Husain: Right, we can grab the subscription that comes out of this, out of subscribing to the source. And when inside of unsubscribe here, we can call subscription done unsubscribe.
>> Jafar Husain: Are we done? Is that it?
>> Speaker 3: Error and complete functions?
[00:02:20]
>> Jafar Husain: Right, if the source errors, we don't want to swallow that error, right? If the source errors, they probably wanna know about it down stream. Our observer probably wants to know about it, so,
>> Jafar Husain: Let's do that, let's be good citizens, and make sure we forward any error that occurs in the source on to our observer.
[00:02:47]
>> Speaker 2: Do we also want to wrap the projection and try, just in case that throws?
>> Jafar Husain: Good, so that's, you're absolutely right, we do wanna do that. So one of the things I'm gonna be doing with this observable implementation is I'm gonna be handwaving some of the error conditions that we can run into.
[00:03:03]
And that's explicitly to keep this code simple, because the goal, so for this implementation, is to help you guys understand how an observable really works. And in my experience, there's no better way than actually implement in it, right? And understand the flow, what happens when you subscribe to an observable.
[00:03:18]
We'll watch that subscription go all the way up to the source, and then we're gonna watch the nexts' flow all the way down. And that's really the goal here, so I don't wanna necessarily do a fully robust implementation of preservable. But to that point, let's just talk about that a little bit.
[00:03:32]
What we would wanna do in a robust implementation of observable, and one that's truly complete we would wanna do something like this. We'd want to account for the possibility that it failed.
>> Jafar Husain: All right, cuz this projection function passed into us, could do something dumb, like a nullity reference, and then we can have an error.
[00:03:57]
>> Jafar Husain: Right, and then in here, we'd wanna call
>> Jafar Husain: Right, something like that. So I'm not gonna put that in here, we wanna stop the observable, we wanna error. I'm not gonna put that in here cuz it's gonna make the code a bit more complicated, you got a question?
[00:04:12]
>> Speaker 2: Would we pass value or would we pass e?
>> Jafar Husain: I'm sorry, we'd pass e, thank you. All right, so that's what we're alluding to here. So this probably a more correct implementation,
>> Jafar Husain: But I'm gonna hand away that a little bit, right?
>> Jafar Husain: And the reason why I'm gonna hand away this, the reason why it's a little more complex, is that we wouldn't be done after we observer.error.
[00:04:41]
We'd also have to unsubscribe, and that gets a little bit more, to make sure that after we call there, we don't send anymore data. Cuz remember how an observable works, you can get next, zero to, well infinite number of times. But if that observable ends, it always ends with either an error or a complete.
[00:05:01]
And then after that, you get no more notifications. So if there were some error inside of the observable, we'd wanna send an on error. And then we'd also wanna unsubscribe from the source, to make sure that the downstream doesn't get any more notifications. Does that make sense? But I'm gonna leave that out here cuz it gets a little bit more complicated trying to unsubscribe, but well you know what, we can do this.
[00:05:23]
This is still not completely correct, but this is something like what it would look like.
>> Jafar Husain: Does that make sense? Let's take a quick look at that understand what's going on there. Now, there is a reason why this is not actually necessarily gonna work 100% of the time, but I'll leave that out for now.
[00:05:40]
>> Speaker 2: What about if the source completes?
>> Jafar Husain: Good question, what about the source completes, right? If the source completes, do we want to send a completion message down stream?
>> Speaker 4: Yes.
>> Jafar Husain: Yeah, because otherwise, right? The source will give us one, two, three and then complete, and then we'll give some transform, three transform values downstream.
[00:06:00]
But then, we won't complete, and therefore we won't free all of their call backs.
[00:06:04]
>> [MUSIC]
[00:06:04]
>> Jafar Husain: So this is a little bit closer, this is still not 100% right, but it's 99% right, Right or not, I think for this particular class. Is there anyone out, what the heck, would anyone has or guess why is this 100% right? This might just complicate things, but I can't help myself.
[00:06:21]
Anybody out there know why it's, what could go wrong here?
>> Speaker 3: Like, it doesn't make sense to me why you would want to unsubscribe, like, in the middle of a map? Because it could fail for only one value, maybe?
>> Jafar Husain: That's a great question, right? I mean, let's say we fail at processing just one value, do we want to not give any more values, right?
[00:06:41]
Well the way to think about, and don't get me wrong, you could completely invent a type, my observable, that behaves that way. But the reason why observable doesnt behave that way, is that it's really trying to emulate what happens inside of a function, just in terms of push rather than pull.
[00:06:57]
If you throw inside of a function [SOUND] that function ends, right? Unless you catch that function, or catch the error and do something about it. In which case, and we will actually show functions you can use later on the class, by which you can handle errors and sort of resume.
[00:07:11]
But in practice, once that function has erred it's done, right? And so, that doesn't allow you to do some things that you might wanna do, and you could always use a different type to accomplish those things. And there are ways in which you could mitigate against this as well, by actually, try catching your projection function, right?
[00:07:28]
If you wanted to do this, you could try to catch your projection function. So there's a lot of different ways in which you could accomplish, preventing a stream from closing, if you got a single error. But by default, we want behavior to match very closely with that of a function, does that make sense?
[00:07:43]
Anybody have a quick guess as to what, I've got a little bit of a problem with this. It's a very difficult case to catch, but the reality is, subscribe can sometimes run synchronously. So imagine, you've subscribe up to an observable and then it on next, your 10,000 values without doing anything asynchronous at all, right?
[00:08:05]
In fact, I think we built a function like that, did I delete it? We had a, I deleted it, but remember, our natural numbers function? All it did was while true and just [SOUND] bang numbers out into the observer. So, the problem is, all that happens and we never get to the part of the code at the bottom where we return the unsubscription, see the issue?
[00:08:29]
So it's possible here, up here, that this subscribe is actually just gonna run. And this code could even get executed before we get the subscription, in which case it would be undefined. Now that's complicated, [LAUGH], it's an really edge case. I don't want us to worry about too much, but I think that this is a more correct implementation, the one we've seen right now.
[00:08:54]
So it's pretty darn close to what it should be. I'm actually gonna revert it to the simpler one, just for the purpose of this. Just for the purpose of this class, sorry, one second, this, sorry. That's what it would look like. So that's very close to how you'd expect the map function to behave, yeah?
[00:09:09]
>> Speaker 2: Do you have to accommodate the asynchronous approach? Could we just use set timeout zero or something?
>> Jafar Husain: Yeah, if you were to use set timout zero in this observable, then you'd be guaranteed to get this subscription before any work started, and then this would work. But, turns out there's good reasons actually of why observables are asynchronous by default, and you can opt into them being asynchronous.
[00:09:33]
This is one of the interesting differences between promises and observables. For those who are aware, promises always notify you in what's called the next tick. I.e., there, it's going to happen asynchronously. It's not going to jump in to the middle of your code, it's gonna wait until the event loop, gives you the next value.
[00:09:50]
And so you don't have to worry about this situation with a promise. If you called that then and passed it a call back, it's not immediately gonna call that call back, it's gonna wait. With an observable, things might synchronously be pushed at you. And I don't wanna get too much detail into that in the class, because it really, for the most part, it doesn't matter.
[00:10:10]
Just like an observable might fire synchronously, just like you can take a cold observable and turn it into a hot observable. You can take an observable that always fires synchronously and turn it into an asynchronous observable, using something very much like what you said, like a set timeout.
[00:10:26]
But this is more detail than I already wanted to go into here. And I don't wanna go into too much more because the reality is, it's not super important at the moment if you guys understand how observable all flows together. So I'm actually gonna revert this out and just use the simpler definition we originally came up with, and leave out the error handling.
[00:10:44]
But I'm glad, I'm glad you pushed me on it, keep me honest, that's good.
>> Jafar Husain: I think this is a little simpler to understand right now. So, in this world, we're just gonna assume that projection never errs.
>> Jafar Husain: Make sense? Simpler, a little bit simpler. Great, so I'm also gonna call your attention to something, which is that we're taking the subscription object.
[00:11:28]
And we are wrapping it in another subscription object, and we're just calling unsubscribe on it.
>> Jafar Husain: It seems kinda wasteful, doesn't it? Can I simplify this program? Why take a subscription, create a new subscription that just calls unsubscribe on that subscription when it's unsubscribed? Can we simplify this program?
[00:11:54]
>> Jafar Husain: What if I just returned the subscription?
>> Jafar Husain: The way to think about this is, and I'm gonna, usually, I, this is the part of the cllas where I might do a little role playing. We're not gonna do anything weird like trust exercises, but we will do a little role playing in the class, right?
[00:12:17]
Actually I'm gonna ask us to just pause for a sec, maybe we can recalibrate the camera. And I'm gonna ask for some brave volunteers for our little roleplay
Learn Straight from the Experts Who Shape the Modern Web
- In-depth Courses
- Industry Leading Experts
- Learning Paths
- Live Interactive Workshops