Transcript from the "Observable Take Function" Lesson
>> Speaker 2: Question on how would you have different things like object.observe and mutation observers Good question.
>> Jafar Husain: Well I mean there's a galaxy of different callback APIs and the browser's only adding more of them. In fact, we can actually play around with object observe and wrap it as an observable.
[00:00:23] There is a very cool example of doing just that. What's the fastest way to get this done? I've actually got an example up on GitHub of using object observe and observable, sorry, first of all, who's familiar with object observe?
[00:01:11] So if I go to a console we can find out if I've actually got this, cuz it's a cool API to try out objects.observe. So you can see it's already in Chrome If you go and load your chrome you'll turn on a particular flag. I think it's right here, experiments.
[00:01:34] No not in there. We can Google it. No? I believe it's under about:flags. So if you go about:flags in Chrome. Here we go. Enable experimental web platform features. So for those of you who can't see that out there, enable experimental web platform features. I believe that is the one.
[00:01:57] So if you enable that and restart your Chrome. And you start typing in console, you should be able to see object.observe. And we can check out how object.observe works.
>> Jafar Husain: I'm gonna create an object.
>> Jafar Husain: Does everybody see the code I just, I'm going to bump this font size up.
[00:02:34] Everybody see the code I just wrote there? So I created a plain old object. I gave it a single property, and then I called Object.observe and I passed in the object and I passed in an event handler that is going to fire whenever we change any properties on that object.
[00:02:51] That makes sense? So let's try it. I'm gonna go, x.name= "Ben." And it worked.. See the console? We wrote out and we actually get a list of changes and notice it says that name changed. It has the old value which is "Jim." And I believe the object, yeah is basically, the object is just the, the object that we passed in the object observe.
[00:03:15] So it gives us the old value and it tells us which property changed. So that's kind of cool, right?
>> Speaker 2: Until you eat up all your memory with a bunch of observers, yeah.
>> Jafar Husain: Well it could definitely be memory intensive to use object observe, and that is actually one of the criticisms of object observe.
[00:03:32] So this is great for listening to one property,but what if you have a property with an object inside of it and it's got a property with an object inside it, and it's got a property with an object inside of it? You can't just listen at the top level with object observe you have to listen to every single object underneath and that, so if you want to listen to a path changing a series of properties and then a change to any of those series of properties you need to recursively add object observe and yes that does turn out to be expensive.
[00:03:57] Some MVC frameworks like this style of synchronizing models and views and so they want to use object observe right but there is probably a fair criticism to say this is perhaps a heavy way of doing object observation. And some other MVC frameworks for example use a different approach which is diffing.
[00:04:16] Angular uses a diffing approach. As soon as an event handler happens. It takes a look at an old copy of the model and a new copy of the model. And then goes through and compares them. That's very different than listening for fine grain changes. Well to be fair object observe is somewhat course.
[00:04:27] Because if I change 15 properties all at once. It will only call that callback once. And it will list in the array all of the properties that have changed. But that still doesn't solve the problem of multiple event handlers at every level of your object observe. I have an example online of using observable to do just that.
[00:04:45] So, it allows you to observe a path, and it uses observable, and it's actually a pretty cool code sample. But under the hood, basically what it does, is it uses switch latest. So let's say I set an object instead of my name Jim. Is this big enough for folks at home to see, you think.
>> Speaker 2: Yeah.
>> Jafar Husain: Okay. So first of all how would I unobserved. Remember async APIs is usually have some way of saying no I don't want more data anymore. Anymore. Well there's a handy [LAUGH] Object.unobserve method.
>> Jafar Husain: Now unfortunately, I can no longer unobserve this, because I didn't capture this handler.
[00:05:24] So I can't even pass it back to unobserve, which is a great example of why that's a very annoying API, right, that this whole idea of like, I'm going to pass a handler, but I gotta remember the handler, cuz I gotta pass it back. It's the same as add that listener, or remove that listener.
[00:05:36] So, the question was how would I wrap object observe as an observable, right? So, why don't we just do that? Because I hate using the object observed unobserved API, I find those API's very annoying because what I really like to use is observable, because I like to use things like take and til or take one for example.
[00:05:54] Let's say I want to listen for the next change to an object, right? One of the operators we didn't write right here and I think we should write, is take. Take, right? We never wrote take and we tried out take in our exercises very briefly and what it does take says right if she's the take observable.
[00:06:14] And let's say she has a number, which is the maximum number of items she's gonna take. If I on next her one, two, and three, by the time I get, if her maximum number is three, she's gonna say to him, on completed after three. And more importantly, you're also gonna dispose of my subscription, right?
[00:06:31] So you're gonna say to me, I don't want anymore data. I've got all the data I need. And you're gonna say to him, on completed. So let's write that function.
>> Jafar Husain: So some of these implementations are a little more complicated to do fully correctly, but I'm cheating a little bit here to give you the overall idea.
[00:06:49] There's a couple of things to call your attention to. For example, when you call an onNext on an observer, if you're an observable and you call an observers onNext. It could throw. And so actually to be fully correct, you should be trying and catching because if somebody is observe, if I call onNext on you and you throw, right, I should then turn around and call onAir, right?
[00:07:10] I should be trapping errors because if nobody's around, with it with async code, your code might not be on the stack at all. So you can't just let a throw on error propagate up with throw. It's observable's job to catch errors, and then push them with onError, right?
[00:07:26] So if I'm being fully correct, I would do that. We just don't have time and it would complicate the code. So we'll just focus on take. So what does take have to do? Take has to return an observable that only on nexts a certain number of items. So the first thing we do, obviously is we got to return an observable.
>> Jafar Husain: And to create an observable, all we have to do is define a forEach function. So what's this observable gonna do? What's it gonna do when you forEach over it? Well I'm gonna do this because we need to make sure to always capture the source observable. That's what this line of code does right.
[00:08:01] When you call take on observable, that take observable needs to still have access to the source so that it can call forEach on me so that I can send it data. So we've trapped a reference to the source observable and we're creating the take observable So just like every other example.
>> Jafar Husain: Well, almost like every other example. In the previous example, we did this. I'm actually gonna start doing something that I know is wrong just to demonstrate what's going on. So we're gonna pass in. We're gonna call forEach on the source, right? That's the very first thing. If he forEachs her, she has to forEach me.
[00:08:39] So, we're going to call forEach on the source. We're going to pass in the onNext handler. And when it receives a value, what's going to happen? Well, notice take needs a counter. We need to keep a counter inside of the take observable because if after we've delivered a certain number on next, We want to stop delivering on next, right?
[00:09:02] We want to say on completed. So we're going to kick declare a counter to keep track of how many on next we've delivered inside of the take observable how many on next methods we call and we'll initialize it to zero. So when an onNext comes through, well we wanna first check to see if the counter.
[00:09:24] What I'm actually gonna do is I'm actually gonna forward on the onNext.
>> Jafar Husain: So now she's onNexting him. Right. She's for reaching me I'm onNext to her and she's on next to him and incrementing a counter.
>> Jafar Husain: Okay, but what happens if the counter gets up to the number?
[00:09:50] What she would like to do is say to me no more data, right? She wants to say never send me another value because I don't want to send him any more values he only asked for three. So I'm not listening to how she going to say to me no more data.
[00:10:05] How do you stop listening for items that you get out of miserable when you call for each on it.
>> Speaker 3: Unsubscribe.
>> Jafar Husain: Unsubscribe did I hear? Yeah. How do you unsubscribe?
>> Speaker 3: You dispose.
>> Jafar Husain: You dispose of the subscription. Now we see that she's actually just returning my subscription to you.
[00:10:21] But that's not good enough now. She needs to hold onto that subscription, so that she can call dispose on it. So we're gonna assign the subscription to a variable.
>> Jafar Husain: And she's still gonna return that subscription object. But she will call subscription.dispose as soon as that number of on next she's delivered, gets up to her maximum number.
[00:10:59] So she'll tell me, no more data please, as soon as I give her in this case maybe three on next, right? And what else does she have to do? I'm gonna add the typical boilerplate which is that you're always forwarding along the on air in the on completion messages.
[00:11:16] All right.
>> Jafar Husain: So we forward along errors so if I tell her error she tells him error, and we forward along completions. But what does she have to do? What's the last missing piece here? So let's say she's a take three observable, she's only going to take three.
[00:11:52] You call for each on her, right do me a favor for each. She calls forEach on me.
>> Speaker 4: forEach.
>> Jafar Husain: [LAUGH] I say onNext one. Right? You're a take three. The maximum you take is three. I call onNext one.
>> Speaker 4: onNext one.
>> Jafar Husain: onNext two.
>> Speaker 4: onNext two.
>> Jafar Husain: onNext three.
>> Speaker 4: onNext three.
>> Jafar Husain: onNext four. Well, after the onNext three, what are you supposed to say to him?
>> Speaker 4: Oncomplete.
>> Jafar Husain: Yes and you have to tell me don't give me any more data right. So we've only done one of those things here we've got the section of code which says.
[00:12:24] You tell me don't give me any more data. What's the last piece that we have to do that we haven't done here. All right, she has to tell you something very explicitly sorry?
>> Speaker 4: Dispose.
>> Jafar Husain: No that we did right here,that's you saying no more data.
>> Speaker 5: You have to call onComplete.
>> Jafar Husain: Right, how are you gonna tell him that it's done? You have to call onCompleted. So if the counter gets up to that number, right, you need to tell him that no more data's ever coming ever. And as soon as she calls subscription.dispose I'm not gonna say onAir or onCompleted.
[00:12:57] As soon as you dispose of a subscription, you're never getting another message from me again. And so now, we have take