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

The "Implementing a Better Object.observe" 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:

With the take function implemented, Jafar uses it to convert the Object.observe function into an Observable. This allows him to fix some of the pitfalls in the API.


Transcript from the "Implementing a Better Object.observe" Lesson

>> [MUSIC]

>> Jafar: Now let's see if we can take object observe, we did it with from event. Can we take this new fangled ES7 feature object observe and turn it into an observable? I bet we can. So instead of in addition to from event, what if we say observable.observations, right?

Because it's plural. Now, instead of thinking of events as this add event listener, remove event listener. Now we're thinking about events in terms of collections, right? It's just another collection. It's the stream of observations we get from an object. So what's it going to accept? Well, it's going to accept the JavaScript object.

And what does it return? Yell it out. What will this return, when you call object.observations on an object? What kinda type?
>> Speaker 2: Observable.
>> Jafar: An observable. It's the same answer every time so far. Return a new observable and when you forEach over this observable, what do we want to have happen?

What's the side effect that occurs? What's the thing that happens to cause us to start getting events pushed at us? What API are we going to call? This new ES7 API.
>> Speaker 2: Object.observe.
>> Jafar: Object.observe! So we call object.observe. So we're going to create a handler, just like we did with from event.

Look up here, we created a handler. I'm just going to copy this code, cuz it's gonna be faster. Instead of DOM addEventListener, it's object.observe, pass in the object and then the not necessarily grammatically correct object.unobserve handler. Notice a pattern? It's always the same thing. We hook up the thing that starts to push stream that's coming to us.

And then inside of the dispose method of the subscription, we make sure that we never get any more events ever again. By unhooking, right? So let's see if we can get this working. This is going to be cool. I'm kind of missing semi-colon somewhere. That's fine.
>> Jafar: Term won't need this up here.

What if for example all we want to listen for a click, and then open a form, and then we want to listen to changes for an object. Until somebody close that for and then maybe update the view because that's what object observe is all about it's about list allowing you to listen to models and when they change updating views, right?

That's how you know the change happens in the model so you can synchronize those changes with your view. So when a form opens you can start listening to changes to an object. And then synchronizing them with your view, and when that form closes you can stop listening to changes to that object, and that's exactly the same thing we did before with the auto-complete box.

When the search form opened we listened for changes to the text box for all for search results and as soon as a close we stop listening for changes. So I'm create an object called person I'm give it the name of Jim.
>> Jafar: And we're going to listen for all the observations on person and since it's an observable nothing's going to happen if I just create it, right?

We have to do what in order to start getting the data out observable. Yeah, forEach. Absolutely. And what actually comes out is this changes array. It's the array of all the changes we made to the person. So in case it wasn't clear before, if I change one property on the object, it's gonna eventually asynchronously give me a change record.

But if I change 15 properties in the object synchronously, one after the other. It will then asynchronously give me a change record detailing all 17 changing. So that's more efficient that way, to wait and to see all the changes in a particular turn and then onNext them and then deliver them rather than just keep calling a call back every single time a property changes.

That's how object.observe works. So change is actually gonna be an array of every change we make to this object. So now that we're listening for the changes, if we turn around and go = "Don"; person.age = 23; right? We should get only one onNext of changes. So let's check it out with our little observable light library.

>> Jafar: How do I clear this console, anybody know? Usually, there's a little button. All right, I don't see a run button, either.
>> Jafar: Okay.
>> Jafar: Undefined is not a function it's complaining about something.
>> Speaker 2: I think you can used observable.observation-
>> Jafar: It's Thank you. It's observable.observation, not object.observations.

>> Speaker 2: And maybe should we call it from observation since we have from event? Kind of that parallel?
>> Jafar: Yeah, sure. Sure, why not?
>> Jafar: Sounds fair. Now I'm gonna follow my own rules here and do formatting, as soon as we have more than one verb on a noun, you put each on its own line.

And I actually already showing the right result. So if we clear it and I run it. Look we got an object with two records here. We notice it says that age change, is hard to see from the formatting but it gave us a record inside that array that says the age changed, and it gave us a record inside that array that said that the name changed.

So it's actually gone up right so now. We can actually make a form like we can actually make a text box where you can enter in the name and a text box we could enter in the age, and we could set that object, and then we could sort of display when a change was made to that object.

Or, for example, we could make an asynchronous network request to save the data, right? Does that make sense? So I've got a form with a text box for the name, a text box for the age. Every time we change the name, or the age for that matter, we might want to kick off an asynchronous request to sync it up with the server and save it.

Does that make sense? What would that look like I wonder. Let's try it. So I gonna open up HTML,
>> Jafar: Right, now we're gonna make it a Save button.
>> Jafar: And we're gonna add a Name box.
>> Jafar: And an age box.
>> Jafar: And this is the type of thing.

Now you're seeing where the benefit of observable is. It's not so much benefit if you're just listening to one data source, you're for eaching over it and you're doing something. In practice, you're almost never doing that in user interfaces. When an event happens, you're usually kicking off some sort of network request, right?

Or doing something asynchronous. And if you try to do that with call backs. You're in callback hell. Because now you've got to manage errors yourself you have to manage on subscriptions yourself. But let's take this is a real example right is actually a very feasible example. Somebody editing a form and then maybe we wait until after a certain batch of changes is finished.

Not every single time a property change for that matter. And then we go off and we make a network request to save it and we're gonna I'm gonna try that out right here. So I'm gonna stop using our observable light library because for this example I wanna actually be able to use the more advanced operators that we haven't defined yet like Cloncat all and merge all.

I'm just gonna open a new one and we're gonna JS bin this. So I'm actually gonna go Add Library, add the RX library, and now in JavaScript, I'm just gonna copy over our definition of object.observable.observations.
>> Jafar: But now, I'm gonna make a couple changes. Up until now, in our simple library, we used a constructor to create observables.

But Rx comes with a helper function for creating observables. But lets us write a little bit less boiler plate. So, instead of going new observable like we're doing here, I'll get rid of this HTML, Rx comes with an observable.create function and it works pretty much identically. Almost identically as passing in a forEach for the constructor.

The only difference is instead of returning this object with a dispose method, which is a good thing about it's always boiler plate the only thing you're ever defining in here is the definition of dispose itself. It just allows you to just pass back, the definition of the dispose function.

So if I was to write this out the long way. You'd see that this was just that if. And under the hood, it wraps it in a subscription object for you. Does that makes sense? So observable doc takes create the forEach and wraps it in an observable. And it takes whatever you the dispose function you return.

And it wraps that in a subscription. So that's all, that's the only difference. It's just a little bit of a helper function to let you write slightly less code. So this should work as is with now that we have rx in here for observation
>> Jafar: So x is the changes array here that occurred to the person.

And I'm going to go. Person.age = 23 and we should see something in the console and expect a token because I'm not on 6 to 5. I'll switch over to use 6 to 5 and it'll understand my error function,
>> Jafar: And then we'll run and it'll, observable not defined, I just have to, now that I'm using RX, we need to make sure to pull it out of the RX namespace here.

So now that I do that? Yes. So we got our changes record right? So we swapped over to using the real Rx. But I can tell you definition very very similar right? Than what we saw earlier. So now that we've got object.observations, let's say we just wanna listen for the next change to an object.

We don't wanna have to like call unobserve, right? We're just doing it inside of our observe handler. You know, that thing, If you want to imagine the code you'd have to write. If you wanted to list the only one dom of that. You'd have to, like inside of your handler, call, remove event listener.

We don't have to do that. So, let's just listen for one observation, okay? Using take(1) I'm going to add formatting here.
>> Jafar: Okay, I don't need the output window either.
>> Jafar: So this isn't going to be too impressive looking, because we're going to see the exact same thing.

The difference is under the hood, our handler is no longer attached that object. So if we make more changes to it, they're just not going to show up. Our callback is not going to get called. So we've listen for the next change to an object and never for another change to an object.

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