I’m sure that a great many of you coming to this article already have an understanding of lazy loading, and if you’re one of those finely educated ladies or gentleman, then feel free to skip ahead to the next section, which I’m sure many already did immediately after reading the heading. For those who haven’t been formally introduced, though, we’ll fill in this void for you.
Concatenation and minification work to reduce the pain caused by wasted code, but it can’t eliminate it, and for the most part it’s impossible to completely eliminate it all. There will almost always be some code that isn’t used by a user, but lazy loading can help a lot in alleviating the amount of wasted code. Lazy loading is loading code only once the user needs it. So if you have a button on your page that will show a completely different screen to the user once it is pressed, then there’s no point in loading the code for that screen right away. You can, instead, load it once that button is pressed. This may cause a slight delay, but it’s nothing the user can’t handle, especially because it’ll only happen the first time because after that, the code will already be loaded, and if you have caching enabled, it may be cached for the next visit. The whole point is to not load scripts until they are necessary. This may sound difficult, but as you’ll see in the next section, it’s actually quite simple.
RequireJS is the secret sauce that makes lazy loading simple. If you’re not already using it for dependency management, go read a tutorial and start using it. Or you can use some other dependency management library, but I highly recommend RequireJS and this tutorial will only be talking about RequireJS.
The key to lazy loading is reacting to user input. So, like I said in the previous section, if a user clicks a button that loads an entirely new screen, the code for that screen should only be loaded after that button is pressed. So, we simply need to use RequireJS to
require some code inside of the button’s event handler.
The biggest difference between “normal” usage of RequireJS and using it for lazy loading is that you use
require within a function that is called at a later time (such as when a button is clicked). That’s seriously the only difference.
Of course, good developers don’t go filling their event handlers with
require statements. Good developers have organized code and separate concerns into different objects and functions. So let’s take a look at how we might accomplish all of this with a standard Backbone application. In the example below you’ll see that I’m keeping a lot of the work inside the router. This is actually pretty widely accepted, but I prefer to keep that logic in a separate controller in my own applications. I’m using the router here to simplify the code a bit and because it’s pretty well known how the router normally works for Backbone applications. Also, we’re going to
So, basically all I did was put all the logic for lazy loading and setting things up into the router, which – unless you’re using a controller – is where it should be.
In my current project, I’ve actually created an abstraction from this, so that the controller doesn’t need to mess with RequireJS directly. It’s called
The constructor takes a single parameter, which is then used as the directory for resources you’re trying to load. You then use its
get method to retrieve any number of dependencies. The function returns a promise, which you can then use
done on to actually complete what you need to do. For example:
The reason I did this is two-fold. First of all, if I decide to use a library other than RequireJS to load the modules in the future, I simply have to update the
LazyLoader instead of searching for everywhere I used lazy loading. The other reason I wanted it is because then I can make a simple API for getting a resource within my application. I simply attach different loaders to certain properties of my applications object. In an application where lazy loading isn’t used, many people will attach all of their view classes to
App.Views and things like that. In an application where we can’t know that the view was loaded we need a way to make sure their loaded, but I still want it to be found on
App.Views. So I use the
LazyLoader like this:
It just seems to make sense to grab a view class using
App.Views.get, doesn’t it? That’s why I made the lazy loader instead of just sticking with RequireJS code. It’s clear what you’re doing.
Of course, this presents a problem when you need to load resources of different types, e.g. a view and a model. But the promise API has ways of dealing with this. I like to take care of it like this:
If you understand how to use promises, then this will all make sense. If you don’t understand how to use promises, then I suggest you read up on them. There are some weird gotchas with the way that the parameters are passed in to the
then function above. I’ll give you a couple examples to show you what I mean:
I hope you understand how that’s working because I really don’t want to put it into words. Anyway, if you don’t want to deal with arrays of modules being passed in, then you can change that last example to something like this:
I guess this ended up being more of an introduction to using my utility class for lazy loading, than an introduction to using RequireJS for lazy loading, but I still got the point across. Try it, see how you like it, and see how much faster it is to load your application! It’s up to you to decide whether a 5-second initial download is worth converting to a 1-second initial download with other small downloads littered here and there, but in the end, your users are the ones who will be the ones who will decide whether they’ll use it depending on those download times. I hope that I’ve given you enough knowledge how to do it so you can go make your apps better. God Bless and happy coding!