Keeping our products fast will always be one of our primary goals. We love fast apps, and keep a lookout for ways to make them even faster. That goes for initial load times as well as usage while inside the app.
Unfortunately JavaScript heavy apps fight against that goal. For example, as additional features make their way into TimePanel, the amount of JavaScript we have to send across the network increases. Caching helps, but has its own limits. For example, the first time a user logs into TimePanel, they’re served the app’s CSS and JavaScript due to a cold cache. Additionally, anytime we deploy updates, TimePanel’s CSS and JavaScript version numbers are bumped, forcing new versions to be loaded when a user logs in. Those are two scenarios where caching doesn’t help and load times are increased.
Normally those kinds of circumstances may not be that bad, but since TimePanel’s JavaScript contain the entire app, its size introduces extra load time that users have to sit through. That JavaScripts lock the browser’s UI thread until they’re downloaded and parsed compounds the matter.
Due to those problems, and how much we value speed, we sought out a way to minimize load times. Enter HTML 5’s async script attribute coupled with a simple preloading technique.
JavaScript, HTML 5 Async, and Preloading
To give a brief background, there’s one main reason why JavaScripts, and their size, are problematic. They block the browser’s UI thread, meaning that until a JavaScript is downloaded and parsed, nothing else happens in the browser. That means a user could see nothing happening for some moment of time, perhaps even seconds, if a given JavaScript is big enough, or network latency is high enough. This is why it’s always a good idea to keep JavaScript small, and if possible, serve them from a fast CDN (a CDN will typically provide better geolocation, speeding up file delivery to the user).
Another way to combat that is to leverage HTML 5’s async script attribute, and preloading.
HTML 5 introduced the async script attribute to mitigate the negative affects we just described related to JavaScript files. With the async script attribute, developers have a way to declare that a script be loaded asynchronously so as to not block UI rendering or subsequent file downloads. This provides a huge step forward toward maintaining a fast user experience while JavaScript files download to the user’s browser.
Additionally, preloading scripts is another way to achieve that. By selectively inserting script tags in a non-interfering way before they’re needed, a user can transparently download and parse a JavaScript file, or other asset, behind the scenes. This doesn’t speed up file loading per se, rather it off loads it in a way that’s transparent for the user. This provides a perceived speed increase, and is exactly the kind of change we just deployed to help TimePanel load faster.
The Changes, and Before/After Results
The opportunity we saw was to load TimePanel’s CSS and JavaScript on the login page. Since we didn’t want to just move the script load time from post-login to pre-login, we added the async script attribute to the CSS and JavaScript script tags.
Edit: Thanks to Silvenga for correcting my use of the async attribute for CSS. He correctly noted that async attributes only apply to script nodes, not link nodes. I’ve since edited my post above to strike-through CSS references, and updated the following screen shot.
That keeps the login page rendering practically unaffected. The JavaScript file downloads asynchronously while the user views the login page, or while entering their credentials. Then, after the user logs in those files are reloaded, but this time via browser cache, resulting in a decrease in TimePanel’s load time, post-login.
Again, the download times of TimePanel’s JS using async on the login page isn’t faster than if it were downloaded otherwise. But, since we’re doing it behind the scenes while the user is logging in it increases perceived performance of the app after login by being able to serve TimePanel’s JS from the browser cache instead of over the network.
And the results are noticeable. Before and after results, taken from Chrome’s network waterfall, show the onload time went from 926ms to 646ms, a decrease of 283ms!
Conclusion
Speed is important, and HTML 5 and other modern techniques offer opportunities to speed up modern applications, despite growing feature sets and file sizes.
If JavaScript, or other performance-sensitive assets, are getting in the way of load times, consider applying the async script attribute to keep the user’s browser UI from locking up. Also consider preloading scripts when possible to have scripts loaded and at the ready by the time user’s need them, without making the script’s download and parse time noticeable to the user.
Hi Guys,
I tried loading the css on my site asynchronously, however it does not work. for eg
google still says that it is not loading asynchronously.
you can check my source and email me if you find anything. Thanks and regards,
Rohit
Rohit,
Sorry for the delay.
Did you add the async property to your CSS tag? Just gave a quick check and it looks like you’ve ommitted that. Try adding that and test again.
HTML5 does not contain async in the spec for use with link nodes – only script nodes.
Quite right. I’ve since edited my post and cited you with credit for doing so.
Thanks for the correction!