Check out a free preview of the full Advanced Asynchronous JavaScript course:
The "Challenge 2: 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:

Taking suggestions from students, Jafar starts to walk through the solution to Challenge 2.

Get Unlimited Access Now

Transcript from the "Challenge 2: Solution" Lesson

>> Jafar Husain: I wanna let you guys know ahead of time this is actually a very challenging problem. And after this we're gonna be doing a problem that's a lot more like the types of problems you're gonna be running into day to day. But I like picking a really hard problem so we can see how, really seemingly pretty tough problems can all be broken down into really small building blocks.

[00:00:19] And so a lot of the challenge of RX isn't learning the small simple functions. Those are so simple to understand you can really memorize them. Really the key to becoming a really effective programmer with RX is a lot of practice, of taking big, big problems and figuring out how to decompose them into smaller bits.

[00:00:38] So today, I'm curious actually what you guys think. What are some, since you tried this, what are some of the harder aspects of this particular problem? What did you find challenging or what are some of the outstanding questions you have, for those who didn't manage to solve it?

>> Speaker 2: Understanding when a task starts and completes?
>> Jafar Husain: Understanding when a task starts and completes. Actually, I think this is probably, single-handedly, the most challenging part about this. Because the reality is, all of these represent next when we get the inner observable. And then we turn around and subscribe to it.

[00:01:18] And all of these represent completes. But almost every single function that I've taught you guys today operates on this, right? When data is nexted inside of these observables, we don't actually know of any function at the moment that sort of is able to operate and get a callback when a next or, excuse me, when a subscribe or a complete is issued.

[00:01:40] And so one of the challenges is figuring out how we solve that problem.
>> Jafar Husain: So before we get to that though, I'm gonna make a simple observation, which is let's take a look at all the data inside of these observables. Do we care about them? Do we care about this data?

>> Jafar Husain: No, not really, right? It doesn't really have all of the changes correspond to subscribe and completes here, right? Subscribe and completes, so how do we go from this, and I break this down just to this.
>> Jafar Husain: How do we get rid of the data inside of? Tell me how we go that first step.

>> Speaker 2: We could filter it.
>> Jafar Husain: Filter it, okay, so go tasks.filter, task, and now what?
>> Jafar Husain: So when I run filter over tasks, every function, the filter function's gonna get called with each of these inner observables cuz tasks is a two-dimensional observable, right? On next observables. So what are we gonna filter on then?

>> Speaker 2: Maybe we would want instead map and then filter on each individual task?
>> Jafar Husain: Right, because if you think about it, we're actually running a map operation on the outer observable because we're trying to transform each item inside of the observable into another item. So actually the outer observable we wanna map over, just as if I was mapping over a bunch of numbers and adding one to them.

[00:03:29] So let's switch this to map, and now that we have mapped over each task, and we have each task, how do we wanna transform that task?
>> Jafar Husain: So now we've got each one of these individual tasks. How do we want to transform them to make sure that they have no data inside of them?

>> Speaker 2: Just task.filter false.
>> Jafar Husain: Yes, this is one of my favorite tricks. Just doing this because if the function always returns false, then all the data inside goes bye bye, right? So that's all well and good, now we've got this. How do we get closer to where we wanna be?

[00:04:11] Well, the big mental leap that we need to make here is I wanna be able to go from this. Because we can't count completes or subscribe using the methods that we've learned today. We want to be able to, what if we could insert data at the front and at the end of the observable, maybe put in -1 and 1 at the beginning and ends of the observable.

[00:04:37] If I had an arbitrary observable and I wanted to put 1 at the front of it, how would I do that?
>> Speaker 3: You could use start with?
>> Jafar Husain: Start with, yeah, start with. That's a more specific, so I could take an observable and I could go start with and I can pass some value, absolutely.

[00:04:55] That's actually a more specific version of concat, which I showed you guys earlier. So remember our observable.concat?
>> Jafar Husain: Right, if I wanna put something at the front of the Observable, I can just concat an Observable with one value to the front. And then I could contact an Observable of one value to the end.

[00:05:17] I like this trick. So,
>> Jafar Husain: Help me out here, guys. How am I gonna turn this,
>> Jafar Husain: Into this?
>> Jafar Husain: We'll take what we have here so far.
>> Speaker 3: Is this where we use scan [INAUDIBLE]?
>> Jafar Husain: Scan? Interesting, well, at the moment all I'm trying to do is, I'm just gonna try and transform this observable into this observable.

[00:05:58] So I don't think we need scan yet.
>> Speaker 3: Okay, map then?
>> Jafar Husain: That's also a good guess. But if we map over an empty observable, what do we always get?
>> Speaker 3: Well, a map with inside of it and a concat operation.
>> Jafar Husain: Gotcha, so we already have this map right here.

[00:06:14] So if we do this,
>> Jafar Husain: And you're right, starts with would be a shorter way of doing this. There might be, maybe there's an ends with also, in which case we might be able to do this slightly differently. It might even be more terse, but at the moment, I'm just gonna do this.

>> Jafar Husain: And now we've got this, right? So first we took every task inside, we got rid of all the goo, all the data, and then we further transformed it by adding a -1 at the front and a 1 at the end. So now, any ideas what we wanna do?

>> Speaker 2: I was thinking we could use distincts with, or distinct, sorry, distinct latest to detect when an Observable starts events?
>> Jafar Husain: So it sounds like you're saying distinctUntilChanged. Is that what you mean?
>> Speaker 2: I think so. Yeah, that's what I meant.
>> Jafar Husain: Got you, so quick reminders to everybody what distinctUntilChanged does.

>> Jafar Husain: Make this full screen here,
>> Jafar Husain: Or not.
>> Jafar Husain: All right, so distinctUntilChanged() takes multiple successive values in a stream and just filters out the subsequent successive values. So if you have the same value multiple times like 5 here, we just suppress the subsequent values that are the same as the previous value.

[00:07:51] So help me understand how do you wanna use distinctUntilChanged here?
>> Speaker 2: I see. I was forgetting one step. So first, I would merge them together.
>> Jafar Husain: Right, so here's the trick because now that we've got a value at the beginning and at the end, now we don't need the structure anymore.

[00:08:07] We can get rid of the two-dimensional observable and we can flatten it, absolutely right. So I'm gonna throw a merge all on there.
>> Jafar Husain: I'm gonna pay careful attention to my formatting because the thing about O Observable is that often you find that we make, let's face it, big fat expressions, right?

[00:08:29] But if you're careful about how you format your expressions, they can be just as readable as structured code. So here I have, you can see that map is transforming the result or merge all is transforming the result of the map, and so on and so forth.