Video details

John Papa: Preload Strategies: Step in Time, Step in Time!


John Papa

Watch all the ng-conf: Hardwired presentations/videos at
ng-conf: Hardwired is brought to you by: - - -
ng-conf is a three-day Angular conference focused on delivering the highest quality training in the Angular JavaScript framework. 1500+ developers from across the globe converge on Salt Lake City, UT every year to attend talks and workshops by the Angular team and community experts.
Follow us on twitter Official Website:


Welcome, everybody. Today's topic is about preload strategies and as to the theme, step in time, step in time, if you like Mary Poppins, well, so do I. So my name is John Popper and I want to talk to you about something I really love. And that's really good user experience. So when you're building applications, people say that it's impossible to create really great user experiences because you always have to choose between two impossible choices. Well, even the impossible is possible. So we're going to talk about how we can make our applications faster or snappier in step in time. It all starts at a little town called Eger and Lazy Loading, now eager, lazy loading, we all know about these, right? We start out and egas like, all right, the users are going to wait for everything to load up front. If you have a large application, they're going to wait for everything to come up front. And a time to their first interaction with your app is not going to be so great. Now, lazy loading is the promised land. Right, we've been hearing about this for years, we have to use lazy loading and users are going to wait until they navigate to a new route. The upside with lady loading is that they get to get in there, see the first screen right away. And then in the background, when you click on a link to go somewhere, the user says, OK, I'm going to go to the other screen. It's going to make them wait to get that other route and load it. But it's still a wait. So it's either wait for everything up front and then it's really fast. That's eager loading or lazy loading is make it really fast to load first and then just load each thing on demand as they click on it. Well, these are two impossible choices. One here to say is that there's a nice in between. This is preloading strategies. This is where you control the entire user experience. Now, it's not as simple as just pressing a button, although maybe it will be when we're done today. But what you do is you control the experience by defining what is the user behavior you want. So we're going to improve that user experience by loading the Joska bundles just when the users need it, just just in time or step in time. So how does this work? So here's a preloading works, imagine that eagerly load of content comes up front, but after so much time on a network, you're going to see the preloaded lazy load of jobs could come later. So here what's happening is the main application loads up front. And after about 10 seconds or so, then the application is usable. That's the time to the first interactive and then the preloaded JavaScript comes afterwards. What this means is that your users can get the site quickly up front. They can use it and then go to other routes. And by the time they go to another route, all that code is already preloaded. Now, why is it taking 10 seconds here? How many of you here? Actually have a superfast network all the time. Yeah, I don't either like conference network or sometimes if you live out in a non urban areas or sometimes you're just your ISP doesn't work so great or maybe it works and places a lot of concrete and you can't get good signals. There's a lot of reasons why people might not get fast Wi-Fi. This is when it really shows up like it does here in this graph. Let's take a look at running a local network here, and I'm simulating a slower speed. So here's the application that we're going to see today. Notice it's taking a while to load so you can got to of one second latency. Now, here's all the eagerly loaded content that's coming now. We're emulating like 3G happening right now. And then suddenly around 11 seconds, the content is loaded and then the pre loaded stuff comes afterwards. So now if I click on admen or villans and other things, those particular routes can get loaded and the users can go to those really snappy. So what happens when you navigate to rule? Let's break this down so you can do this yourselves first. The router is going to make a network request to download a module. So makes sense, right? You click on a route and then what happens is inside the router, it says, do I have this lazy, loaded bundle currently in the browser? So it's going to check to see that, and if it doesn't, it's going to fetch that bundle. And once it fetches that bundle, then it's going to cost users to wait, right? So depending upon the speed of your app, the speed of your network, how you've preloaded that wait time could be a little bit different to be small or it could be big. So we're going to look at different preloading strategies now, there's a couple that come out of the box. Thank you. The default behavior is probably nothing. That's our just basically work with lazy loading and don't preload anything. Only get the JavaScript as the user clicks in around. There's another much more aggressive preload, this one sounds great at first it says get everything up front. It's extremely aggressive, but it also increases your network traffic and the usage. So think about this. If you've got an application with a lot of modules and there are large and you're on a slow network for your users, if your users have preload all, you're actually going to be occupying the network, loading all that JavaScript while they're trying to use your application. And they might not even need all those bundles loaded. So you might want something in between. And that's where we're here to talk about his custom preload strategies. This is how you can control that customer experience. So the way preloading works is like this, after each navigation, the router is going to check to see, hey, do you have any unloaded modules? If there's any unloaded modules, then it's going to say, all right, should any of them be preloaded? And that's based on your logic. So the first step happens automatically and then it's going to check your logic to see should any of them be preloaded. And if so, it'll actually preload those modules so you can decide which ones you want to put up front, which ones you don't. The place that you define this and set it up in Europe, if you're not familiar with it, is right here. So here we've got preloading nothing, that's nothing at all, that's the default. So inside your router models for route, you pass this second option, there's routes and a preloading strategy that says basically don't preload. That's the default. Or you can preload all things. You get a preload, you get a bundle and you get a bundle. This is the other option is the other side of the extreme. That's where we're going to do everything for our customization. So should you preload everything up front? Maybe it's something you have to think about, but if you don't want to, there's a couple of options. Now, I'm going to show you three options, because I like the rule of three, three different ways to preload your JavaScript bundles. You can opt in or opt out. You can basically pick here's a bundle I want to preload, here's a bundle. I don't. So you might have a customer orders app and say, I want the customer site that bundle to be preloaded, but I might not want the admin piece to be preloaded. So you can define this at design time. Another way to do it is to check the network speed, I've worked on many large apps where sometimes they're in a place where they know they can have good speed and other times around mobile devices or they're on cell phones or they're having to sell devices tethered to computers. If that's the case, you might want to check the network speed before you preload. Why do you really want to, on a 3G network, download something that might be one Megg? Maybe not. Another option is to predict the preloading strategy based on the user's behaviors. For example, if somebody goes to a page or going to a shopping site, they're looking for Lysol wipes because they want to clean everything in their house. They want to go find those. They go to the shopping site. They look for the search page. Once they get to the search page, you know, with a fair amount of certainty based upon analytics that they're going to press search and that's going to bring them to search results. And then once they find the thing they want, they're going to go to the search details. So if those search results and details are in a different lazy, loaded module. Couldn't you predict that if they get to the search page, that you could automatically go ahead and load that there's certain behaviors we can look for and I'll show you how I can look for these and how you can code them. So how do you create these custom preload strategies before we get to the demo, we have to understand that we have got to implement an interface so ANGULAR gives us preload strategy interface. We write our own logic that basically defines exactly what we wanted to do because we control it and then we just apply it to the roots. So in a custom strategy, well implemented. We can set logic up for that function and then we can apply it super easy, three steps and it's time for a demo. OK, so we're inside of our code base and we're going to see this a couple of times today and I'll share all the code with you later. Right now, I've got three strategies in my application. We're going to take a look first at this opt in strategy. Here's how you define it. So in my optimum strategy, I've defined as opt preload strategy here. It's a class, it's a service provided in the route and it implements the preload strategy interface and then it defines a single function called preload, which accepts two arguments, the route and the load. The route is what's given to you. So you can then determine what route did I get? And then the load is a function that you can run if you want it to preload, and if you don't, you can just pass empty, which comes out of our ass. So here we're checking to see with optional chaining is an optional training suite with optional training. I can check to see if I've got a route, which you should. And it's got a data property with a preload property that is also Truthy. So even if it has the properties at the falls, it wouldn't work. But if it has the property with any value in it, that's basically not false or false. It's going to load that route. So what does that look like? Let's look and see where this in previous strategy is used and go find all references here. We can see that model is using it. So we'll flip over to at model. Now, inside the module, we can scroll to the bottom, we can see down here inside of our route, we can set the preloading strategy right there. Now, I'm going to set that to opt in preload strategy. Now, if I get some of these comments and I put these in so you can look at them afterwards, take them away for now. You can see that this is just inside of the router module in my application, very simple preload strategy, often preload. Now all I have to do is go to my router file into my router file. I set up which routes I want to preload. In this case, I'm saying heroes should preload villains to preload. I want the admin to preload, I'm setting them all up. Let's go ahead and turn off. The villains actually just delete the line of code entirely. And we'll do it this way, CNN Heroes, villains, admen, and we're not doing this about, so we run over to the application itself. And we'll pull it over here. Now, I'm going to reload the application and we're going to go inside the network tab. Drag over the tools. And look at what's happening now. First thing I'd like to do is I'd like to type in module up inside the network tab that's going to filter all my network traffic. And then I'm going to refresh over here on the left hand side the page and you're going to see I'm getting all of my heroes bundles first. So I got the heroes bundles that works for me. But what else did I get? Did I get any other payloads? Let's take a look. So I go back into my code here and I can see that in my application. I've got the opt in. And the option is here, and I go to my router and I can see I got my preload true for different settings, and then I get to go my strategy and see if my strategy is actually in place. So once I've got all that, those different modules will preload when I need them to preload. The second kind of strategy that I want is going to be an on demand preload. So OnDemand is a little bit different on demand means that you get to decide when you're actually going to preload this stuff. And we were some comments for now. There we go. So if on demand, it's a little more implementation to code this, what I'm looking for here now is I'm going to pull in a service called my preload on demand. Pre load on demand is a service that gives me a notification. So basically it's listening for observable so I can then act upon that. Whenever somebody tells me to preload something, I'm going to run this function. It's going to listen for it. And that's going to determine this if there's a pre load check. So preload check, what does that do? It says, hey, do you have data preload set on and is the route and its path? Right here is that route path inside of this option that you sent. So basically you're going to pass the path in for what you want to preload and it's going to match it to another to what's inside the router. And if so, it's going to go ahead and preload. So it comes back and say, if I should preload, then return load or otherwise return empty. And that's the whole deal of it. So the strategy is super simple with this one, the real work is inside of this observable. Let's take a look at where this service exists and what it's doing. So we find all references and come back over into the strategy itself. We can see we've got our strategy here, but look what's happening inside of our service. Here is our preload service, and it simply defines a subject. And that subject is implementing some options, and one of those options is going to be we can just click on it. You can see up here you get the right path and preload sets a true but false by default. So then they create a subject and get the observable, and if somebody calls this function called start preload and they pass a path, let's say they pass heroes, they pass villains, it's automatically going to then say, you know what? Go ahead and set those preload option to true for this route. Pass and subject next. So this this method right here is called start preload on line 13. That is the thing that's going to kick off a preload of whatever route you want. So how do you implement this? Imagine inside your navigation, you've got a router link and in your router link, there's my rattling for heroes. When I mouse over a particular menu item, I want to preload whatever routes associated with that. So all I have to do is pass in the menu. What am I want on this case? I'm going to pass in heroes. That's going to preload that. Here's my villans route, I want to pass an villans. And then for this one to pass an admin and then about and the code for preload bundle is down here, I just go and call my service, start preload pass at the root path, and then it's all good to go. So to make this one work, then we just have to type in the name of that particular field service in this case, that's our on preload strategy right here, and that comes out of our previous strategy that we used. So it's important right there. And then if we make sure we've reloaded our page. Now, if I click on a button or I hover over a different menu items, I could go ahead and preload anything that I wanted to. So that's where the things were preload for us automatically. The last one is when I have a strategy that is a little more clever about where the user is. We talk about network aware. Now, did you know that there is a Navigator API that comes with the browser? Now, most modern browser support this. In fact, almost all of them do. So you can check to see if there's a navigator connection object if there is. I'm doing two different checks here. I'm saying if the person has their mobile data save or option turned on, then don't bother preloading anything because I don't want to slow them down if they're trying to save data. If they're not, they're just using a good connection, then you can say, all right, what is the connections that you want to support if they're using slow 2G or 2G? I don't want them to preload. So therefore I'm going to return false. But if they're on 3G or 4G, I'm OK with this and I'm going to go ahead and preload. So I'm using the network information to find out how fast is their network and then we can go ahead and preload the content as they want it. So it's really up to you and how you implement this and the guard logic here. It's just nice to have it because what if they're not using a browser that supports this navigator that happens to be in here? So then you end up with all that. The nice thing about these three different strategies that we've seen is that you can actually mix and match those to do it any way you like. So you can run this demo at the links that'll show you at the end, but just in hindsight here, what do we do? We've got a network where strategy that we walk through. That's the one that checks to see the network that you have. That's really good, especially if your users might not always be on superfast Wi-Fi. You've got an on demand. This is where you choose how it works. In this case, I'm choosing that when somebody hovers over a link or they press a button or they do a certain action on the page based on user behavior, then I'm going to go preload that thing because then the users might get that page that come up instantly by the time they actually click or do something with it. And then there's the opt in strategy and that one, you can basically set a flag on the routes at design time to basically decide which ones will preload and which ones will not. So, again, customising Prioleau strategy, pretty simple, you decide when to do it or when not to, you can implement the interface, you define your logic in this case or using the data preloaded to determine if you preload or not, and then you can simply add it if you got the preload option inside of your roots file. Then the network where strategy, we've got the save data saver and then we decide which network connections we want. I like to debug this to make sure I know which connections are popping up in my applications. But in the end, it's up to you and how you define this, and if you do this, your users are going to have a much better experience. So final tips for you all. I highly recommend that all of your applications define your preload strategy, pick the one that you want. There's other combinations that you can choose as well. And you can grab these three that I created up from the repository that you're going to see in just a moment. And if you want to not have to worry about writing these different strategies, you can use the snippets that I have at this link. It'll actually automatically fill in different kinds of preloading strategies right out of the box for you. So if we go back and look at this real quick, let's say I had nothing in that file. If I come up here and I type in preload, you can see there's a preload network right there. There's a pretty good networking strategy. If I want to type in Fonthill smaller on a type, an opt in, there's the option strategy. All you have to do is type in a dash preload and you'll see several different options here for precleared strategies that you can use. Now, you could, of course, write your own custom one any time you want. That'll work as well. And if you want to see the repository, all you have to do is go to. GitHub Aghajan, Papà, angular preload, and there is the code that you can get for this entire thing, and I uploaded it this morning and everything is tour of Heroes, of course. Thank you very much for coming today. And I hope that you have a good time and that you preload strategies to all your applications.