Check out a free preview of the full Asynchronous Programming in JavaScript (with Rx.js Observables) course

The "Observable Map Function" Lesson is part of the full, Asynchronous Programming in JavaScript (with Rx.js Observables) course featured in this preview video. Here's what you'd learn in this lesson:

Jafar revisits the implementation for the map function. Only this time, instead of adding it to the Array class, he implements it on the Observable class. Since it is on the Observable class, map will call onNext and pass the appropriate projection function.


Transcript from the "Observable Map Function" Lesson

>> [MUSIC]

>> Jafar: So we got from event. Now let's see write map. Remember when you wrote map over array. I bet you it's not so much harder to write map over an observable. So what's going to look like to write map over an observable. Well we've added for each of the prototype, let's add map to the prototype.

Now what does map take? Explain to me how map works again, remind me. What it's argument? What's the only argument to the map function? Now map is on the on the array object, in this case map is on the observable object. What does map accept as it's one and only one argument?

A function. A function to apply to every item that comes through the stream. Remember we said that observables are like a hot potato. Every single item that comes through, we're gonna translate it and hand it off, right? We're just gonna keep calling call backs all the way through.

So let's write map. So map accepts what's called a projection function. Which is, long story short, is just a function that you apply to every item that comes through, and you take the result, and then forward that along. So what does map return? An array when it's on an array, but when it's on an observable it returns?

>> Speaker 2: An observable.
>> Jafar: An observable. So right there, we need, we know that we need to return an observable.
>> Jafar: And when the for each function of that observable is called, what do we do? Well one thing I'm gonna do, and you guys have probably done this in JavaScript before, I'm gonna capture the current this object.

Who's written code like this in JavaScript before? A few people. So one of the very complicated things about JavaScript that is not intuitive Is that functions do not execute necessarily against the object in which they are created but they execute on the object on which they are on if you call that object when they're on.

so a dot function, when you call that function. This will be the a object, not the object where the function itself was created. So when we call this inside of here, this will be this observable. It will not be the observable that we use, that we called map on to create this observable.

So we need a way, remember what happens. We're gonna step through through this now again with human beings. I am the source observable and when you call map on me, you create her and she is the mapped observable. And now when you call for each on her right, call for each on her.

>> Speaker 2: For each.
>> Speaker 3: For each.
>> Jafar: I say one, and let's say you add one to each item I give you. On next one.
>> Speaker 3: On next two.
>> Jafar: Right. On next to five
>> Speaker 3: On next six.
>> Jafar: On completed.
>> Speaker 3: On completed.
>> Jafar: Yeah right. So it just keeps, we just keep handing it off.

We just keep sending messages along. We're going to demonstrate this right now. So the point is when you call out for each on her she has to call for each on me and that's why I have to capture the this object here because this is the mapped observable.

>> Jafar: Right? And when you call for each on it, her, she has to call for each on me, right? So how else is she gonna hold on? Remember the observable is the this object inside of this function. Is the thing that you're calling map on right? So we need to capture it.

So I'm going to code var self equals this. And then as soon as you call for each on her she's gonna call for each on me.
>> Jafar: Now, for each takes three callbacks or an observer, in this case we're gonna use the three callbacks, right. The first callback is the callback we get when we get called with data.

So what is my responsibility at this point, right? She's calling for each on me, right. And so this is the part where I say on next one. What's your responsibility. Now when I say on next one, your responsibility is to do what?
>> Speaker 3: On next to.
>> Jafar: Right, on next to him the result of applying the function to what I just gave you, right?

So what does that look like? Well here, this is him, he's listening right? He's listening and so we have to call observer on next x, but first you're going to apply your projection function. You're gonna call the projection function on x before you give him the value.
>> Jafar: That's almost done.

We're almost done now. That's all there is to it, right. When you call for each on her she calls for each on me, which in this case is self, right? I on next her information. I'm gonna actually write this out so it's clearer.
>> Jafar: I'm calling her on next.

And she's calling your on next. But first she's translating it, she's running it through the function before she pushes it to you.
>> Speaker 4: So does she call projection function?
>> Jafar: Yes. She is the mapped observable and you are the person who's calling her for each method and you're passing in your observer, right?

And then she is in order to give me, in order to give you my data translated, she has to for each over me because that's how you get data out of an observable right. You have to for each over it so she for each's over me. I'm the self here, I'm the this object.

On the observable that you called map on, right? That's to the left of this map. It would be, and then you'd create a mapped version of that observable. That's what we're turning at the top level, the mapped observable. And then when somebody for eached over the map observable, the mapped observable has to for each over the source.

And I on next data, and she on nexted to you. She's just forwarding it along like a hot potato. So on next, that's all well and good, but what happens if I say on air? What are you going to say to him?
>> Speaker 3: Well, if there's no retry, then I say-

>> Jafar: And apt observables don't do any retrying, right? So, you forward on the air call.
>> Jafar: And what's the last possible message that I can say to you?
>> Speaker 3: Completed.
>> Jafar: Completed. At which point what's the logical thing to say to him? Yeah, because I'm not going to send you any more data.

So obviously you're not going to send him any more data, right?
>> Speaker 4: So can I put the observer on subscribe or terminate or?
>> Jafar: As soon as she sends an uncompleted message to you, yes, it's the observable's responsibility to technically unsubscribe and make sure that it It cleans up after itself, right?

Because I, well, the interesting thing is, here, map doesn't really need to clean up after anything. It's actually the source that needs to clean up, right? All she's doing is forwarding on messages, right? If she makes sure that I'm never gonna send a message anymore, then, by extension, she's never send a message anymore.

And notice what I'm doing with for each, here. What's coming out of for each? What's the object that's returned when you call for each on an observable?
>> Speaker 5: Observable?
>> Jafar: Nope, not an observable. When you call for each on an observable what pops out?
>> Speaker 5: A range participant.

>> Jafar: Nope, let's go back to this example.
>> Speaker 5: A subscription, no?
>> Jafar: A subscription, right. When you call for each an observable, a subscription object pops up because that's your way of saying no more data please. And so, what we're doing inside of this map, this mapped observable, it's kind of elegant, because she doesn't need to create a subscription object to hand to you.

She's actually just gonna take the subscription object I hand to her and hand it to you. Right? Because if you call dispose and you cause me to never send any more data to her, well by extension she's never gonna get any messages to send to you. So she's just saying, " thanks very much for that subscription.

Here you go. Like she's handing it right to you. And that's all there is to map. All we need to do is take every on next I give to you, and forward along to him, after running it through a projection function. And on error and on completed you just forward it along.

>> Jafar: Should we try filter?
>> Speaker 4: Where are we handing that subscription off?
>> Jafar: Right here because we know, I'm the source, right? I'm gonna say on next one, on next two, on next three. As soon as you see for each, the floodgates are open and I'm just going to say on next, on next, on next.

But as soon as you call for each on me I'm gonna hand you what? Every observable hands you what when you call for each on it.
>> Speaker 4: The subscription.
>> Jafar: The subscription object. Because you need some way of saying I don't want any more data. And so as soon as she calls for each on me, I'm going to hand her my subscription object.

That's what comes back from from for each, right? That's why we're just returning for each, so I had her my subscription object. And she just turns around and hands it right to him Because if he disposes of my subscription object, what does that mean? I'm never gonna send her another message.

And what does that mean? She's never gonna send him another message because all she does is wait for me to send messages and then forwards them along.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now