Check out a free preview of the full Asynchronous Programming in JavaScript (with Rx.js Observables) course
The "Observables as Animations" 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 wraps up the course talking about how Observables can be used to sequence animations in a user interface. He also revisits the concept of syncing data with a database.
Transcript from the "Observables as Animations" Lesson
[00:00:00]
>> [MUSIC]
[00:00:04]
>> Jafar Husain: But I wanna call your attention to those three flattening functions we talked about earlier. Just everybody tell me what the three flattening functions are?
>> Speaker 2: MergeAll.
>> Speaker 3: ConcatAll.
>> Speaker 4: SwitchLatest
>> Jafar Husain: Right, so let's say, and this happens all the time in user interfaces, I start an animation and then another animation comes along.
[00:00:26]
What are the three options I have when it comes that previous, so let's actually imagine, spatially. Can we get a white board going? That would be super helpful right now. We're about to talk about how broadly applicable these three flattening patterns are, mergeAll, concatAll, and switchLatest. And how we actually can use them to coordinate animations.
[00:00:46]
Right, so let's just do a quick review of how these flattening patterns work. So I've got an observable of observables here. All right, here is the beginning of the outer observable. And within we have an inner observable, another inner observable and inner observable. And mergeAll it's like lanes merging on a highway.
[00:01:02]
So we get five, six, nine and 77. ConcatAll, each one of these shifts to the end, because we always handle them sequentially, top to bottom, left to right. So we get this very long time period, because we don't start for each over, and therefore generating these results until this is finished, and that's why we shifted over here, and so on and so forth.
[00:01:26]
We get this long observable. And finally switchLatest where we begin listening to an observable, and then as soon as another observable comes along, right? We switch to it, and actually I got this wrong, because there's no five here.
>> Jafar Husain: This is the right observable for switchLatest.
>> Jafar Husain: Because we started listening to an observable, and before the second one came along, this one came along, sorry my time is a little bit off here.
[00:02:00]
But the point is this is the time axis. And so another observable came along before we even got five, which means we only ended up with nine. So if I was to visualize what these operators would do two animations. So let's say we started an animation that animated a box from, this is 0,0 to 100.
[00:02:20]
And all it looks like is it literally just looks like this, it looks like [SOUND] An empty observable, because all it does is it starts animation and then as soon as that animation is done, it says uncompleted. So, there's no data inside. So, if we model our observables as animations, we can do them this way.
[00:02:38]
And then by the time this reaches here, one second will have elapsed. So, let's say this is one second of duration right here, 1000 milliseconds, okay? To move 100 pixels. So let's say we start that animation and half way through, we start an animation that moves the y position of the box up to 100, so halfway through we start that animation.
[00:03:04]
So that's actually an observable of observables, the first observable like the first inner observable that comes along, starts the animation going this way but then half a second later another inner observable comes along that starts pushing the y up this way. Now I'm gonna draw a path for this box, and you guys are gonna tell me which flattening pattern accomplishes that path.
[00:03:33]
>> Jafar Husain: It got half way and it started moving up at the same time as it's completing moving this way. And then eventually it got to the top.
>> Speaker 5: MergeAll.
>> Jafar Husain: MergeAll, absolutely.
>> Jafar Husain: Right, because we're listening to the current observer and as soon as the next observable comes along, we immediately start playing it, and now we're pushing the box x and y up at the same time, till finally the x animation completes.
[00:03:56]
But we still have that half a second left on the y animation and so we can that's structure right there. When you're coordinating animations, you can either play them at the same time. You can do the next thing, which is,
>> Jafar Husain: Which flattening pattern would this be?
>> Speaker 6: ConcatAll.
[00:04:16]
>> Jafar Husain: Concatall. We fully finished the x animation before we even start the y animation, and so we get that. And obviously, by process of elimination, we get this. All right, almost, technically it's gonna look a little more like this.
>> Jafar Husain: We got halfway through the x animation and we stopped.
[00:04:40]
And then we moved all the way up the y animation. When you dispose off the observable, you freeze the animation, just right in place. Now you can make your decision about what that does when you dispose of an observable, when you're designing the API that wraps an animation as observable.
[00:04:55]
You could decide that when somebody dispose off of it, you would snap it back to its original position. You could also decide that you could snap it to its end position, but that's how I would do it, by default anyway, if you dispose off the observable that represent that animation, it just freezes in it's place.
[00:05:10]
So this is a nice visual explanation of how flattening patterns work and how you can use them to coordinate animations, right? If you treat all your animations as observables, you can coordinate them just using these three flattening patterns.
>> Jafar Husain: Does that make sense? Okay, so I don't know how much more we can cover today.
[00:05:36]
well, I think we're gonna cover the one last thing which is saving the database. which is at service time that model changes, we're gonna save the database effectively. But I wanna ask you guys a question. So before we turn the projector back on, I wanna get your intuition about it.
[00:05:53]
So we've got this stream of changes to the object, right? And we're going to map it, because this is always what happens, we map it into attempts to save the database, right? So for every single time, we get a change the object, we are going to issue a save to the database command, which is gonna return an observable.
[00:06:11]
So, right off the top, how many deep is that collection, if for every change to the object we create an observable, which saves the current state to the database? Two, right? Because for every little of those change record, those arrays of change record, we're substituting in an observable that will cause us to save the current state to the database.
[00:06:35]
which flattening pattern would we use to flatten it on out? What's the right behavior?
>> Speaker 4: Switch Latest.
>> Jafar Husain: Why Switch Latest?
>> Speaker 4: Cuz you don't need the older data.
>> Jafar Husain: [LAUGH] Why would you want to keep trying to save old data, right? You wouldn't, you'd wanna save the latest data.
[00:06:50]
Absolutely, so not really that surprising, in user interfaces mostly you want to do the latest thing. So I'm not necessarily gonna type that all out now because every single example I've shown you up till this point has followed the exact same pattern. Let's map over some event, let's issue an asynchronous request, we'll take a look and we'll see that, sure enough, we've created a two-dimensional collection.
[00:07:10]
And then we'll choose the right flattening pattern, which on the UI 90% of the time is switcLatest. But I've just shown you that's for asynchronous requests. There's that last step, which unfortunately, I couldn't get to today, which is fine, now I've saved to the database. Maybe I wanna show some animation that indicates that's complete.
[00:07:26]
Maybe I wanna fade a dialog box in and says, Save right? Then that's one more asynchronous action to the chain and you can bet that will involve going to a three dimensional observable, right? And then you wanna decide what flattening pattern to use for that third level. Maybe it's switch latest, or maybe you want to smoothly show and hide animations one after the other.
[00:07:49]
When you're doing animations, switch latest is not always the best pattern, right? Do you wanna start an animation, then flicker and switch to another animation? I can tell you Netflix for XBox One application, wrote a drop down list. And we used the exact same technique that you saw there.
[00:08:02]
But there was one extra step, was that when we showed the results, we didn't just flicker them in. We animated them smoothly, fading in and coming from the right hand side. And then as soon as you clicked the key, we faded out to the left hand side. And then when the search results came in, we faded it back out from the right hand side and so on and so forth.
[00:08:20]
What we definitely didn't wanna do, is start fading that animation in from the right hand side and then have you click and then immediately have a jerk and fade out from the left hand side, do you see what I'm saying? So, maybe you wanna use concatAll to make sure your animations are smooth.
[00:08:36]
So I'm sorry we didn't get to animations, asynchronous requests and events, but it's the same thing again and again. You're going to map over a stream, you're going to pick the right flattening strategy, that's the hard part. You learned how to flatten streams with arrays. The only question that now that you have to deal with when you deal with asynchronous programming, we've really summed up the challenges involved in asynchronous programming to one question, which flattening do I use?
[00:09:00]
What's the right way to coordinate this concurrency? That's what we're doing here. We're coordinating concurrency, things happening at the same time. That's all it is and it turns out there's only three common patterns. So when you look at asynchronous programming from the right level, when you take an half of a step back and look at it, sure enough it's actually really simple.
[00:09:23]
But if you walk all the way up to it and look at these little callbacks, and these handles, all of a sudden it seems impossibly complex. And so most problems are really about zooming out and finding the right level of abstraction to tackle them. And I suggest to you guys that events as collections is the right level of abstraction to tackle asynchronous problems and user interfaces.
[00:09:44]
And so now it's up to you to go out and master these skills, drill them, try them in real applications. Because I can tell you that everybody at Netflix who learns this technology, very often they come up to me within two or three months, because that's often how long it takes of thinking about it and paying with it, and say I've completely changed the way that I write user interfaces.
[00:10:03]
So I hope the same for you. Thanks very much.
Learn Straight from the Experts Who Shape the Modern Web
- In-depth Courses
- Industry Leading Experts
- Learning Paths
- Live Interactive Workshops