Transcript from the "Exercises 28-30" Lesson
>> Jafar Husain: Now that we've seen what this observable is capable of, right, let's see how it works.
>> Jafar Husain: So, first let's take a look at the way that we conventionally do. It's just reactive programming, right? Asynchronous reactive programming. Let's take a look at the way that we conventionally do reactive programming.
[00:00:21] So, I've got a button and I've got a handler for that button. And as soon as the button is clicked once, I just wanna unsubscribe. So, in other words I wanna do something, I wanna alert, print up an alert box as soon as you click a button. And then, as soon as you click that button, every other time, I never wanna print the alert box again.
[00:00:40] So, let's see how that works. We'll add an event listener, so I'm adding a function. And then I remove that event listener the very first time that handler is called, but I also alert a message that the button was clicked. So I'm gonna run that, gonna to click this button, okay.
[00:01:02] And now every other time I click the button, nothing happens. So relatively simple stuff right, this is the type of code that you write when you write event driven code. Where maybe you this is a good example of something you might do with window.onload for example, right? You might subscribe a function to on load and then do something once.
[00:01:16] And then hopefully you remember to unhook your event handler cuz technically that would be a memory leak if you didn't do that right? You might if you, that's a common mistake in programming if you leave your event handler on on load, right. You might accidentally in your closure be holding onto a very big object that you might've only needed temporarily.
[00:01:31] That's one of the dangers if you're working with closures. If you happen to use an object inside of a closure and then you don't free that handler, that closure will hold onto an object that might be big and expensive. So it's always good practice to unsubscribe from window.unload.
[00:01:46] So now if we convert a click to an observable, we can see that we can do the exact same thing in a slightly different way. So we don't think about things in terms of add event listener or remove listener anymore. We now know that observables are collections just like arrays and we can use all the same operators that you've been using on arrays with observable.
[00:02:06] And so one of those operators is forEach. Adding an event listener is no different than traversing a collection, that's really what you're doing at the heart. So I will first adapt this button click into an observable and then I will just forEach over it. This code is doing the exact same thing as the previous code.
[00:02:22] Now notice that when I forEach over code I get the subscription object back. And the subscription object is just a way of me saying, as the consumer of the data, I don't want any more data. So I can dispose of that subscription object. So I'm gonna forEach over and the very first time I get a click, this should say click.
[00:02:41] I'm just going to dispose of the subscriptions and that means I will get no more messages. So this should run the exact same way as the last one. So I click it. Stopping Traversal, so that means I've called subscription.dispose. And now, nothing right? So now hopefully we've seen that events and observable, you can accomplish the same thing, right?
[00:03:05] By calling subscription.dispose. Just a slightly different interface. Instead of calling remove event listener, you call subscription.dispose. Now one of the very nice things about observable that is not true of events is that observables can end. You remember yesterday we talked about those two missing semantics that the gang of four who wrote the design patterns book left out of the observer pattern.
[00:03:25] Now that we've added them to observable, we can take advantage of this notion of completion. So instead of after getting one message we as the consumer saying okay now I wanna unsubscribe from the event. What I want us to do is I want to rather than unsubscribe from events or by calling subscription.dispose explicitly, I want us to use operators to create events that end when we want them to end.
[00:03:48] So wouldn't be great if we could just say, hey look, just take this event and just fire one. Just essentially, transform the observable so that only fires once and then immediately completes. Here's the brilliance of an observable. Which is that when it completes, when you have an explicit completion message, when that observable tells you it's done.
[00:04:07] Is there any reason at all for it to hold on to your event handler? No, let's say I'm the observable and she is the consumer. She hands me an event handler and I push her values one on next one, on next two, on next three and then I say on completed.
[00:04:25] I've just told you that I'm never ever gonna send you another value, right? Is there any reason in all for me to hold on to the observer, to those three event handlers that you gave me? No, I can just free them. That's what's great about an observable, it cleans up after itself.
[00:04:40] That's why when an observable completes and it says I'm done. You don't need to go along and say, yeah remove event listener. It's already freed your event listener for you. That's the difference in the way that you think about DOM events and observables. That's why we don't worry about unsubscribing from event by calling subscription.dispose, that's just machinery under the hood.
[00:05:00] We're not gonna use that API directly. We are gonna take the observables and we're gonna take operators that I'm gonna teach you today that cause them to end when we want them to end. And then we can just be 100% sure that they're not holding on to our callbacks anymore, because they've told us that they're never gonna call us again.
[00:05:17] So this is how we avoid memory leaks, memory leaks are a serious problem in large user interfaces. Where you're subscribing up to events all over the place, and you got to remember to unhook from those events. It leads to what we call state machine like code. You need to build a state machine.
[00:05:31] I need to remember if I'm hooked up to the event or whether I haven't. Let's go back to that mouse drag example. I want you guys to imagine for a moment how you would have written the mouse drag example if you didn't have observable. What would you do?
[00:05:42] You'd probably listen for a mouse down, right? And then when you got the mouse down, your event handler would fire. And then you'd hook up to the mouse move. But now you have to remember that you've hooked up to the mouse move, right? So that when the mouse up comes along, you can unhook.
[00:05:55] So you're writing code that's like using variables to keep track of what's going on, right. So okay, well, I'll hook up to the mouse move and I'll hook up to the mouse up. And if the mouse up fires I need to remember to unhook from the, I need to remember to rehook up to the mouse down.
[00:06:09] You write this code it's all kind of like this do this and do that, right. It's very easy to forget, in a particular circumstance, to forget to unhook your event handler. But when we write code like this you'll find we do it declaratively so it's much easier. So there is an operator that you can write over array we never bothered to write over array, but it's very trivial called take.
[00:06:29] Take is something that you can apply to any observable and simply say I just want one of these. So what that will do is it will take an observable, which remember this observable is based on click, and observables based on DOM events will never say onCompleted. Why is that, why is that observables based on that we've adapted from a DOM event will never give us an onCompleted message?
>> Speaker 2: Because it will keep listening to the DOM event forever.
>> Jafar Husain: Right, cuz DOM events don't have this notion of completion right. DOM events just go on. That was the thing that was left out of the pattern twenty years ago. They just thought, who needs to say we're done, right.
[00:07:08] So if you take a DOM event and you directly adopted into an observable, the observable never say onCompleted. But we can make the observable say onCompleted by applying take one to it, right? So now instead of, back to the example of window.onload, right? A good programmer remembers to remove their onload handler after it fires.
[00:07:28] We know it's only gonna fire once, right. But we've got to go and remember to unhook that handler. Otherwise we could leak memory cuz of that closure could be holding on to some data. Well that's kind of ugly code. You've got to nest your remove event listener inside of your event handler, and it's just ugly.
[00:07:42] Why don't we just convert window.onload into an observable and then do take one? What that's gonna do is instead of just calling onNext the one time onload would have called your event handler. Now it's gonna call onNext, onCompleted, right, cuz it's take one. What take does it take an observable and says, look, you just want to take this many number of elements, and then you want to complete.
[00:08:02] And as soon as that observable calls onCompleted it's gonna free our event handler for us. So we don't need to go back and add or remove event listener. So if I take this button clicks and do take one. Notice I'm not even, I'm just ignoring the subscription object, I'm not even using it directly.
[00:08:16] I almost never call subscription.dispose when I write RX code because I've got take until and I've got take and I've got switch latest. So I almost never actually explicitly unsubscribe from an observable. If we run this, we'll find that it does the exact same thing as the two previous examples.
[00:08:33] So we get a button click, and I get no more button clicks. Because it's unhooked the event handler under the hood for me. Because I've told it to limit itself to only one element. So this is the power of giving observable the same semantics that are on the iterator pattern.
[00:08:51] Now that an observable can tell us it's done, well that would be the logical time for the observable just, you know free our subscription. Why hold on to a call back if you're never gonna call it again?