Rob Wormald (@robwormald): Angular & RxJS at ng-europe 2016

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
so as he said I'm here to talk to you about reactive angular 2 my name is Rob Wormald advocate on the angular team at Google so being a developer advocate means my job is basically two things so part of it is what I'm doing here so we come out to conferences and we go to companies who are using angular we talk to them to advocate we'd tell you how great all this stuff is the other part of my job is talking to developers and feeding information back to the core team a lot of what we do at Google is using the different kinds of infrastructure than than we do here in the outside world so like we don't use webpack things like that so a big part of my job is saying to the core team hey this doesn't work with webpack normal humans aren't gonna be able to do this kind of thing so it's kind of a two-way job and so this is the fun part of it sometimes so we're gonna talk about reactive today and so I am mildly obsessed with reactive programming like it's probably not a surprise to most of you that I'm here talking about our XJS right this is pretty much what I do through here so when we talk about reactive programming angular it kind of breaks down into three or four different api's and either these are kind of the main ones that I think about there are other places under the hood where we're using reactive programming and observables but these are the big four and these are the ones I want to go through with you today this is the fifth one which you probably don't know about it's a little bit of history on this this is almost two years ago now yeah almost two years ago now Jeff cross sent out a message to the angular data dev group so this is a google group and this is long before I joined the core team and he sent out a message that said hey surprise we're gonna switch over to observable spring Euler to do HTTP is gonna be using observables you know we're gonna move over to this this brand new pattern and this was before I joined the core team and so I basically was like oh my god what and so I wrote this big long diatribe and there's actually like 10 posts where I'm continually going no no no no right and saundra who's in the front row here was actually arguing for it so thanks for that right and so this was kind of my primary thing here right is that I I think that they're really interesting I think they're they're really pretty awesome but I don't want to make it harder for users right like everybody who's using angular one had just finished really figuring out how promises worked if you're new to JavaScript right and so this is more or less how I felt right that like I just gotten promises I just understood and now they were taking them away right and so if you feel like that and this is a question that comes up all the time now people ask me all day long do observables make sense why are we not using promises you know why why are you doing this to me why do I have to learn this new thing and so this is a really good issue to read if you haven't there's a lot of discussion here goes to a lot of our kind of reason and rationale but this question comes up it's a fair question to ask and I think that's the thing that I really want to answer for you today if you haven't really gotten into using observables for me observables are about composition so it's not about just HTTP or just forms or you know just any other reactive API it's about being able to think about what you're doing in a single way an observable is something that you can really use to represent many many different kinds of things many types of different data flows and if you're using observables for this it means that it makes it really really easy to plug one thing into another thing write one API that you've got because it's an observable out and the other thing takes an observable in all you have to know is how to cook sort of connect these pipes together so let's that's what we're gonna go through today and kind of see if I can get across to you what I'm talking about when we talk about composition so this is a joke that comes up often on Twitter right so anytime somebody talks about observables and mentions type-ahead boxes take a shot take a drink right this is a drinking game that we play and this is this is the reason we do this is I think this is probably the best example for understanding what we mean when we talk about composition just back to here so these are the three we're gonna use in this example here so angular has to form ap is right there's the old school old school the traditional style ng module ng model API where were you're doing two-way data-binding you're mutating the data that you're using in a form and then we have this new reactive forms idea and this is for me kind of the the entry into observables in angular 2 so rather than doing ng model and binding to some object what we're doing here is binding to a form control and so a form control does not represent your data it represents the actual control on the screen and it gives you an interface to talk to that thing so the way we use something like this is we start with a very simple component I'm just emitting the decorater at the top here because you've all seen what angular decorators look like all I'm doing is creating a new control and just creating just attaching that side to the my control property here what this gives us is a couple of different API so the first one here is value changes so value changes isn't observable it will emit to you it will push to you the value of the textbox every time it changes right so you type in the textbox a new value comes down the pipe for each letter that goes into the pipe so this is a stream right this is an input into your program so to use this and the other way to do this is status changes right so we have the data that's coming out and also the validity of the control based on the validators you're using all of this will be delivered to you so you get again text spitting out to you and also basically a true or false that tells you this form is valid or this form is not valid so these are the two inputs into the system we're not gonna worry too much about the the status changes today and we're gonna work with this value changes property so again to start with this is just a stream of text right every letter you type you get text spit out to you so let's build a type-ahead right let's go through this kind of step by step the first thing you want to do is bring in the HTTP module right or the HTTP service this is the built in angular 1 which again uses observables and we'll see how these things compose together in a second here first thing you wanna do is inject HTTP and then what we're going to do is write if I'm typing in an in pub books unlike to say it let's say I'm going to query YouTube or something like that what I need to do is take each letter that I'm typing in the Box write the word that I've entered and turn that into a URL turn that into the thing that I'm going to use to actually do the search so the first step here is to just use map this is just like array map the abuse before takes one value in you return the new value and so all we're doing here is taking the text adding it to this this API string here we're using a template string in here so what we get out of here right would be the URL with query attached to the ends and now you can see our subscribe is going to deliver to us the URL we want to use so simple stuff so far the next step is to use flat map now flat map is probably the move important operator in the entire thing we're gonna talk about here flatmap is very much like map its job is to do a transformation from one thing to the other but unlike map what it will actually do is wait for the observable you return from it so HTTP here again returns and observable so if we were to just straight map that right what we would actually get back what would you admit to us would be unobservable and we don't want that right we want the result of the observer wall this is very much like promises that promises unwrapped right you need to get the value out and that's what we care about so flat map will we'll take in that URL return a new observable and flat map will wait and deliver the results of this HTTP query and so the next step then is to actually get the response object so HTTP returns to us a response observable this response object has JSON on it so again top to bottom we're getting the text we're turning it into a URL we're making a request with that and we're getting a response out with me so far just a little trick if you've been doing this before Ben Lesh who does all of our rxjs stuff always yells at me because I forget to show this slide onstage so I'm gonna slow it to show it today flat map has this really neat second to property here which allows you to basically do what's called the results selector and this allows you to do an extraction do a transformation inside a flat map so it just saves you from writing this this extra line of code right so again top to bottom start with the text turn it into your arielle take that URL turn it into a request and now what we're getting out here is actually like the array of JSON responses that we want right now anybody who's ever built to type ahead knows that the most important thing about type Ahead's right is that you are always going to want the latest value if you've started typing in a box and the query goes out to the server and the server starts doing its work and then you decide actually want to type another letter you no longer care about the previous request right and it's it could be possible that one request goes out a second request goes out and then they might arrive back in a different order right there's a bunch of things here that can kind of get really tricky to manage and if you've ever done this without observables you've tried to do this for like set time out or anything like this it becomes a really really ridiculous problem to manage so this switch map operator here works exactly like flat map so again it takes in a it accepts observable and then it unwraps that observable and delivers you the value but if a new value is emitted into it right so again I type 1 2 3 and then the request goes out and then I type 4 it actually will cancel the previous request for me so we'll go ahead and cancel the underlying request and this is actually the reason that we don't use fetch which I was arguing for two years ago and we started talking about this is that fetch doesn't give us the ability to cancel a request right because it's using a promise we have no ability to cancel that request we can't abort it in flight and so it means that even if we don't care about the results of the bit of that query coming back we're still paying the cost of the bytes right we're still paying for that network traffic and especially on mobile devices on 3G networks things like that this can be very expensive right so switch map gives us a very very easy way to go ahead and just cancel previous requests it keeps everything in line for us it keeps everything nice and efficient and everything works really nicely so again text URL request response automatic cancellation here and so what you would do you kind of the sort of simple naive way to do this would be to just have a results property right on your on your controller on your components and then at the end here just do subscribe and then you know do this dot results results which would make it available to your template and so you know we can just do a simple ng 4 here and iterate over those results and and render the content right this is the neat API that I really like and I think this is this is the thing that really makes what you're doing with when we start doing composition when we start doing reactive components it makes it really easy to think about because you don't actually have to really think about this isn't observable you don't have to worry about subscribing and unwrapping it and getting all the values out what we can do is instead of subscribing at the end here we're just going to go ahead and assign this observable to this dot results so rather than results being an array here results as observable of arrays and so the interesting thing about observables is each time that you call one of these operators so map switch map or whatever it will always return you a new observable so all we're doing here is taking this you know going through this sort of flow we're going through and assigning that to this start result so now this start results is an observable of our responses coming back from our server and then if we go ahead and use the async pipe here the async pipe will go ahead and automatically subscribe for us it will wire up the observable it will start the work happening it will unwrap the values right so we don't have to that subscribe unwrap thing the other cool thing about the async pipe is that it's deeply plugged into angular's change detection so it means that because this value is being pushed to us by the stream the async pipe can listen for that and it can use that to actually plug into angular's change detection so imagine if you've got a very large complex UI you've got a lot of change detection happening this allows you to really take an entire let's say a very complex list view that's rendering these results bring it out of the change detection cycle and so when the application that's doing this thing it will actually skip over this list view when doing change detection and when the async pipe receives this receives a value it will tell annular hey this is a new value you need to go ahead and do change detection forming here and so this is a very powerful tool when you start getting to much much larger and more complex UI eyes so that's inside the head right again we start with our as this results that's being assigned we're doing our value changes filtered now one of the things that's interesting here is that when you're typing in an input box you probably don't want to do a query with like the letter A right it doesn't make sense to just send out a out to the server and so you probably want to wait until you've got a couple of letters or two or three letters in the box right so we're just going to add filter this is a simple optimization and so this means no values will come past the filter pipe unless the text is longer than two characters right so again we don't want to send kind of tiny queries to the server the other thing we want to do is be cautious about how often we're sending these requests out right so D balance is something this is a pretty consistent pattern for this again if you've ever implemented debounce manually using set timeout it's a really complex thing to do because you've got to deal with the set timeout you've got anywhere got to worry about keeping track of the ID of the you know the time math you've got running out at the moment so there's a lot of extra state there's a lot of extra complexity to manage it's very very complex - Doody bounce without observables here it's just one built-in line of code debounce time we'll do 150 milliseconds right so type of character - 800 milliseconds send the request out so it's two little bits of optimization that are very very very easy to do with our X and just ridiculously complicated to do without our X now so these two things here right this is like a consistent optimization you're gonna do on most sort of type-ahead things you do and so what you probably don't want to do is rewrite this repeatedly right do this again and again and again so an operator that not many people know about is this let operator I think this is actually one of my favorites in rx what let allows us to do is take that little bit of logic that filter and debounce logic and move it out into its own function and so what we can do is say let's do filter and debounce as its own function this function will accept an observable accepts an input stream and then we just have to return a new observable back from it right so it gives us a sort of pipe section we can plug into any sort of observable stream so in this case we're going to take the input we're gonna dot filter it right do the debounce and to apply that we just use the let operator and we can pass our function in this is super super useful for reusable logic this is doesn't have to have di you don't have to get involved with it it's a very simple function that you can reuse all over your application you can also get a bit clever here and do function copies interests with this stuff so this is we're just going to expand that function slightly and this is going to be a function that returns a function that returns an observable of our stream so this allows us to pass arguments into it for example so this time we're going to take the delay in then take our input stream filter and debounce it based on that delay and to use that we can just do filter in T bounce and call that function and pass the arguments in so you can do this you know to a kind of a crazy extreme but this is a very useful thing to have reusable bits of logic can compose into slightly larger usable bits of logic share them on github you know they become very very portable nice little functions so the router is the other big observable thing in angular 2 the first two iterations of the router had some kind some basis and observables there were some things you could listen to but in general the first two iterations of the router were mostly based on promises and when you think about it initially that makes sense because you're going from A to B right and you you want to make sure that that completes promises make sense as a mental model for that but when we looked at the second API or when he looked at the third API building the router and one of the things that had happened is that in the interim of us rebuilding routers the ng RX team had actually built a whole brand-new reactive router right so they kind of totally thrown out an entire idea of how we were doing routing and really built a new thing up from scratch and I think that when we as the team looked at this thing it became pretty clear that this was maybe a better model for how to think about doing routing how to think about applications and how to think about you moving around your application because this is really it's a stream of actions it's a stream of routes query parameters all these things are inputs that are consistently changing to your system right so it makes it it gives us a really consistent API to work with with with routing so imagine we wanted to build like a list detail view right so we can use angular's router to this we have a list on the left side we have a detail on the right we might have our list of users coming off the server here and then want to render a kind of you know the users profile on the right box here so if you think about the left side that's going to be a list component right we'll call that our list component we're gonna just bring in an imaginary user service here this user service is gonna have a fetched users method method excuse affection users method which returns an observable again so this users becomes an observable abuser we're just going to assign that I really like this because again there's no real logic in here there's nothing really happening you have to think about this too much it's just a question of basically using this component to connect your service and its data to your view right it's a very thin layer a very nice reason easy to reason about kind of connector and then our details component will be the right side thing you know the thing that will show are our kind of consistent user profile that's going to inject two things it's going to inject the user service and it's going to inject the activated route so the activated routes is delivered to every angular component that is routed to it will give you the information about where you're at what parameters you have arguments things like that and the first observable API in the activity route is params right so if you've got user : ID in your your route configuration route top params will deliver that information to you and interestingly rather than if you go from user 1 to user 2 rather than destroying that component and Riaan Stan she ating it right what this allows you to do is keep the same component on-screen reuse that repeatedly and just react to the parameters changing right so again this is going back to the idea of composing this stuff you can actually almost think about this exactly the same way as our form control right this is just an input into the system it's a stream of information that we can then pick up on and start doing interesting things with so starting their user service what we're going to do the other thing to mention here is that we have our activated route params here and then we're outer actually exposes query parameters right so the question mark on the end of your URL that's exposed as query parameters as well that's exposed as an observable that we can subscribe to we treat query plant params as a global thing query parameter global to your entire application whereas activated route and their specific params are only specific to the route that you've activated on so there's two ways to handle this thing both of them observable again both of them using the consistent interface so again we'll do this whole thing again right so we're gonna do route params we're gonna flat map we're gonna get those parameters coming off of our routers as we navigate around flat maps gonna admit to us this new value each time and then we're just going to call our user service with a method like get user by ID we're gonna pass in the params ID this will make a request to a back-end server you know again returning and observable here and you know rendering that back out so we're just gonna get the user profile back from this call one thing that's nice about this going back to that switch map idea right it's new for a user who's clicking around your application in a very fast way right so it goes from 1 2 to 3 to 4 and there's a delay while the API comes back this will again automatically cancel the in-flight request for you so it keeps things efficient it means you're not wasting bytes and it's just one line of code to add that to your controller so again we'll do our subscribe here user profile block it out so just to refactor this a little bit again we'll go back in ahead and eliminate the subscribe from our from our component we don't want to deal with that we don't a mess with any of that we'll just assign the user observable to the component and then we will use the async pipe and you know in the template to do this one thing I would have mentioned and Victor pointed this out to me before I came here he said you have to mention this right you have to talk about this is that basically we see a lot of people who are subscribing and then unsubscribing right so they're managing the subscriptions manually here the neat thing about the router is you don't actually have to worry too much here about cleaning up about unsubscribing you can just listen to the thing and then when that component dies that observable will die and the listeners will die and so you don't have to worry about memory leaks with the router in this case it's a really really nice clean way to deal with things so this is what it would look like if we took that observable that we've attached to our view right and and rendered it now I don't know about you but I don't think right now that this is the nicest syntax right because we're worrying here about two things worrying about the asynchronous pipe here we're wearing about async pipe and then we're dealing with our our question mark right and so this is the we call the Elvis operator we get yelled at when we call it the Elvis operator so I think it's called the safe navigation operator music oh not if that's fish meat she doesn't know either that's why we call it the outside right so the Elvis operator will wait and it means if that value is undefined or null it will not try and resolve the next value so this means it doesn't explode with you know name is not a defined party so it's something that it's safe it makes things easy to work with right but I don't think that it's particularly beautiful yes the other gotcha about this that you should be aware of is that what we're actually doing here is subscribing three times this observable right because each of these async pipes is currently subscribing to the observable now this is less problematic in situation like the router but because observables can be recibir if you actually subscribe to something like an HTTP request several times will actually send out multiple requests out to the API which is generally not what you want so there's a couple of ways you can handle this one of the things you could do is want to use one of the built-in operators like share or there's you know share we've got cache we've got published behavior there's a number of different ways to handle there at the observable level the other thing to do is actually think a little bit differently about how you layout these components this is a pattern that we'll talk about here in a second and this is a pattern that we very much learned or I very much learned from react and Dan Abramov and things like this this is a way to think about how you compose views in your application so let's refactor this slightly right so we're gonna take our detail container component this doesn't change very much we're going to assign the dis dot user to our controller and this week you know this is what we're doing a single subscription to but instead what we're gonna do is instantiate a new component we're gonna create a new component to actually host our profile so we kind of call these things smart and dumb components or you if you prefer presentational components and logic components or there's a number of different ways to describe this but really what we want to do is divide up the responsibilities of these components right so we want to have one component whose job it is to talk to the server to go get data it's very specific to the place that it lives in your applications these smart components they're gonna do di so we're go back and look at this again this is a smart component right it has dependency injection it's pulling in services this is not something that you typically reuse in multiple places in your application and trying to do so will often lead to your code being more complicated than it needs to be so what you do is sort of accept the fact that this is a very thin component that all it's going to do is serve as the interface between the outside world and the bit of rendering that we want to do it so if we create a profile component here we just create our template notice in here that we're not dealing with asynchronously at all there's no async functionality in here there's no Elvis operators there's no question marks it's a very very simple component the net result is the same right but inside of this you don't have to worry about any of the stuff that's happening in the outside world so the profile component just takes input from the outside world so it's got an input it's got a user right and so all we really have to care about here and all the component has to know about is it as handed a user it's handed the user object and its job is to render it doesn't care where it comes from doesn't care if we're using it in a test or if it's coming off server or we're using it in the router so this profile component becomes very very reusable and more importantly becomes very very easy to test right because you don't have to worry about mocking it out you don't have to worry about any of this stuff it's a very simple reusable component and so then we want to use it right we've got our original user profile header and then we can just use our user profile components assigned to the input property there so I'm going to bind with our our user brackets here and then we use the async pipe once right so this brings all the logic into a single place the async pipe here handles that single subscription handles the values coming and off for the server allows us to really not worried about that component on the inside so one kind of missing piece for me in angular 2 right now is we've got a really really good story for how to get observables from services from the router from all the various observable api's and angular and so we can do a really good story on output to the view right model two views is really really well done at the moment and we've got a really really good story for data coming off of forms right we talked about the forms API so when you're typing input boxes things like that we've got a really really good story for that and I think it works really well the thing that we're missing at the moment and this is an API that when we get back from this I really want to start working on is how do we think about all the other events that are coming in from your interface right so if you consider something like drag and drop right that's not something you can describe in a form or button clicks right we can currently do the sort of the parenthesis syntax and assign to a method but if you're thinking about this stuff observe leave if you're thinking about this in a reactive way again really what you want is the input into your system to be unobservable right and that means that downstream from that you don't care about what's coming from it it's just an observable of data so this is kind of an experimental proposal that we've been working on for a little while and the idea here is that very much like the query decorators that you have in an angular today so you've got a few child and few children and and content children and content child which query for elements in the view right so view query allows you to say I want to find the some components observe child for example and we're working on the name so if you've got suggestions send them in because we don't love this name at the moment this would allow us to query for the sum component right and also then listen to events coming off of it clicks drags whatever ditto for the second one there which is actually looking for a selector or for a target thing and we can listen to any custom event coming off of that so this would give us the ability to do really really powerful composition and say all data coming in from these views is an observable and then it's easy to switch map flatmap all this stuff that we were just talking about really to make the whole story end to end observable so this is something that interests you we've got an issue it's four zero six two on the angular repo I'm gonna get me some trouble here and say if you like this API Miche goes in the front row so come and tell him that this is something that we should do right because I've been trying to convince him for a little while cool that's it for me I'll be here all day so if you have questions comments you want to talk about observables come and see me I should mention I was talking to paulie yesterday if you want to get an idea for how this works in the real world what it looks like to build a really complex really solid type-ahead for this kind of stuff look at ng bootstrap because I've done a really really good job with their type-ahead implementation to get it sorry okay he's gonna show you later a real and real world example of this and so it means it's not something we're just showing on stage is something that I think actually works you like it yeah it works good great so that's me you
Info
Channel: ng-europe
Views: 6,926
Rating: 5 out of 5
Keywords: YouTube Editor
Id: WWR9nxVx1ec
Channel Id: undefined
Length: 28min 34sec (1714 seconds)
Published: Fri Oct 28 2016
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.