So, I’ve already said I agree that HTTP request reduction is very important. But it isn’t the final answer, mostly because there is no final answer, only a helpful set of principles to guide you on your way — it is only part of what you need on this journey.
What else is there to consider?
If you have less than 5k of JavaScript loading on your site, you’re not likely to see much appreciable difference. But if you’re like a lot of sites on the web these days, you have frameworks, ui widgets, plugins, analytics, social bookmark sharing scripts, and so on… you blink and you’re loading 50k, 75k, even 100k of JavaScript. And some of you use heavy JavaScript frameworks where the file size, even gzip’d, is well over 250k. Throw in some custom font-face files (all the rage these days), and it’s not surprising to see even 1MB of scripts loading!
Whether you have 50k of JavaScript, or 500k, if it’s all in one file, the browser is going to load that file byte-by-byte, serially. Someday maybe we’ll get multi-cast BitTorrent’ing of our page resources, but that’s not a reality now.
So, concat’ing all your JavaScript into one file completely eliminates any possibility that the script code itself can be loaded in any way in parallel (though with LABjs, as mentioned before, you can still load that code in parallel with other page resources like images/CSS/etc).
If you have 100k of code to load, in one file, the user will wait for that entire file to load all at once. But, if you were to take that 100k and break it up into even 2 files of approximately 50k each, and you used a dynamic loader like LABjs, both files would load in parallel, meaning in approximately half the time of the original single 100k file.
True, you’ll pay some slight overhead for the second HTTP request, but if you’re talking about larger (>50k) files, it’s still likely to be modestly quicker than one request for the larger and serially-loaded file.
You have to balance this technique out, because loading 10 files of 10k each is probably not the best answer either. There’s some complicated formula which will determine the sweet spot between one 100k file and one-hundred 1k files — and what that balance is will probably vary from site to site. I can say in my case, I usually try to get it down to 2, maybe 3 files, and that’s usually pretty good performance. The point is, loading only 1 file is going to hinder an important optimization method, dynamic parallel loading in favor of saving the small (but non-trivial) HTTP request overhead. And there’s a point at which that type of tradeoff is actually detrimental to your site. So maybe you should re-think how you construct and load your files, or at least experiment with some variations?
Don’t forget the cache!
I’m not sure about you, but I can’t remember the last time I wrote and deployed a JavaScript file and then left that entire file alone for more than a few weeks or months at maximum. In reality, I tinker with my files constantly, because I’m always improving and tweaking them, both for run-time performance and for improved user-experience.
If all of your site’s code is in one file, and you change even one character of that file, the next time every single visitor comes to your site, they’re gonna re-download the other 99.999k unnecessarily.
Sure, the user’s browser cache is not fully reliable and a significant portion of views happen with empty caches, even with return visitors. But that doesn’t mean we should throw the baby out with the bath water and completely ignore the browser cache as being irrelevant. We should intelligently try and figure out what code is less likely to change, and what code is more likely to change, and separate the two code segments into two files.
That way, our tried-and-tested framework code that changes rarely doesn’t have to be re-downloaded every time we tweak other frequently changing code that animates our banner ads, etc.
Again, you can’t just create a dozen separate files and expect to have optimum experience, but I’ve found that splitting the lines between two (maybe three) levels of tendency-to-frequently-change gives pretty good overall performance. For instance, my frameworks and third-party plugins that I use, which I almost never change, I include them in one file. But for code that initializes the page and plugins and controls site-specific behavior, I include that in a second file.
Just because the browser cache is finicky, don’t completely ignore it as an important tool in optimizing overall user experience, not only across subsequent page views but also subsequent visits.
And what about those remote files?
This is a part of the conversation that seems to almost universally get ignored when I hear arguments for JavaScript concatenation. It’s like people take completely for granted that code loaded from a remote source (hopefully a CDN) is not only a reality for almost all sites, but also that it loads basically for free. This is not true. There’s still HTTP request overhead involved, just not on your server! And yes, it’s probably much less against a highly optimized CDN than against your little server farm, but that doesn’t make it ignorable.
A lot of people learned a valuable lesson a few months back when Google Analytics went down (a rare occurrence), and millions of sites all had that awful “document.write()” garbage in the bottom of their page that GA suggests for including their JS file. What happened? Most pages failed to finish loading and initialize, and the users were all held hostage helplessly as a result.
But that wouldn’t have been true if you loaded that remote GA file with LABjs. My sites didn’t suffer that fate! If done correctly, the loading of the “ga.js” file simply would have failed silently, but the rest of the JavaScript loading and initialization would have continued as normal, and users would probably never even have known that the outage occurred.
The reality is, most sites on the web load one or a couple of files from remote locations. And it doesn’t make sense to self-host these files so you can concat them in with your other local scripts. You need to load them from their remote locations, and you need to do so in a way that is optimized and robust. The <script> tag is not the right way!
But a loader like LABjs will let you easily and seamlessly load one (or a couple) of files from your own server, along with a couple of files from other locations. And, you can even easily queue up initialization logic for the various different script resources separately, so that your code will load and initialize, even if the GA code fails to load because of another outage.
More to the story
This is really just the tip of the iceberg. There’s a lot more complexity to this issue, far more than I could ever cover in even a couple of blog posts. But I hope you can see there’s enough questions to be answered that something like LABjs as a script loader is worth looking into. We can’t just sit by and blindly expect that one answer (reducing HTTP requests by JS concat’ing) will ever get us the most optimum page load behavior. We’ve got to be a little more creative than that!
Pages: 1 2
