I recently gave a talk about JavaScript Loading at JSConf.EU in Berlin. Video/audio of the talk will be made available online eventually, and I will link to it here once that happens. But, in fact, I will be re-presenting this same talk at the November meeting of Austin.Javascript (@AustinJS), on Tues Nov 17th, at 7:30pm. Come join us if you can! My hope is to push the envelope of how we all approach loading JavaScript resources into our pages.
The talk covers a number of different strategies, each of which I will be covering in subsequent posts here. But I wanted to give a quick overview of what you can expect:
- Build-time optimization: it’s important to utilize build-process optimizations to manage local scripts and dependency chains. Depending on your server architecture and frameworks, there are lots of different choices that you have here, but the key is have a system that can manage this intelligence for you, freeing you and the other developers on your team from having to maintain the techniques yourselves.
- Load/run-time profiling: We’ve all heard the advice that the best way to get JavaScript resources onto the page is to only have one JavaScript file, meaning we should always concat all our individual files into one massive output file as it goes to the browser in production. But does this always make sense? I believe it only rarely does.
There are a number of tools for profiling your site/application at load-time and at run-time, to decide what parts of your JavaScript are critical to load at the beginning, and what parts can be safely deferred until later and be lazy-loaded. Doing so not only speeds up the load time user-experience of your site/application, but it also often helps create better long(er)-term user-experience by more effectively utilizing the user’s browser cache. You can profile manually, or automatically, but you shouldn’t ever put a site or application into production without at least examining these strategies and trying a few different options.
- Post-optimize your minified JavaScript: For a long time, it felt like the book was closed on minification/obfuscation. There’s only so much white-space you can remove from a JavaScript file, and only so many variable names you can shorten, before a script seems as small as it’s going to get. But, it would seem there are more chapters to be written, yet.
Recent releases of projects like Google Closure prove that there’s a lot more ground to cover on what we can do to optimize and shorten our scripts. I also have a project called Mincir which is aimed at specifically running post-minification optimization steps on files to squeeze out more bytes. Smaller files means quicker loading and better user-experience. And that means happier users and happier developers.
- Dynamic, on-demand, parallel loading of JavaScript: While the landscape of how the browsers handle the <script> tag is quite diverse and often ugly, there are ways to normalize this behavior cross-browser, and in the process allow all your JavaScript resources to load at the same time, in parallel with each other and the rest of the page assets. This is actually not that hard. But ensuring proper execution order, not only of loaded scripts, but also of coupled inline script executions, is where the magic happens.
Luckily, a project of mine, called LABjs, does just such a thing. It’s a general purpose, flexible, and capable JavaScript loader, that allows you to load just about any script or group of scripts onto any page, at any time.
- Load and cache “not-code”, execute “code” later: Sometimes, the best way to get JavaScript onto the page is not to load JavaScript at all. This may seem like a crazy statement, but you actually have some options as to how your “code” gets delivered to the page. For instance, you can transfer the code inside a multi-line comment block, or even as an escaped string literal assigned to a JavaScript variable. You may ask, why would I do such a crazy thing? Well, it turns out that there’s a significant amount of time spent processing JavaScript once it’s loaded onto a page.
So, if on one page you want to “preload” a script into the cache for use on a subsequent page, like you have done with images for years, you pay a penalty for that script simply being added to your page. Unless of course it’s not really a script at that point. If it’s a comment or a string literal, then it is loaded and saved into the browser cache, but there’s almost no processing time on the page at that point. Later, on another page, you can recall this “not-code” from cache, and transform it into executable code.
This type of technique is quite valid for desktop browsers, but is particularly helpful for mobile browsers where the biggest bottleneck is not actually usually the connection speed but the processing power of the mobile device in handling large amounts of not-used-yet code while rendering a page.
None of these techniques are in and of themselves a complete solution to this issue, nor are these ideas the final word on the topic. But it’s time we evolve how we load our JavaScript onto pages and move beyond the 1990’s version of the plain ol’ <script> tag. I hope this talk and these posts will get that ball rolling.
