A blog by Ryan Breen of CloudFloor
Include is itself a fairly small chunk of JS which is designed to run within the browser of development and production users. This approach has some nice advantages: there’s no need for server side compression scripts and it’s easy to create many different compressed files depending on the different library requirements in different parts of your application. Expanding on that last point, you can select at browser load time which library to use within a specific page giving you runtime flexibility.
The one thing I don’t like is that Include is packaged as a separate .js file. As I’ve discussed here many times, performance in modern broadband networks is dominated by latency. The round trip time to request the initial include.js, which is only 3kB, will offset some of the gains from compressing and concatenating library files. In most use cases, the best performance approach will be to use include.js to compress your libraries only during development time, replacing all include.js references in production with a single compressed library call per page.
Last September I posted about a CSS sprite generator designed to reduce the tedium of a popular HTTP optimization. The developers responsible, Edward Eliot and Stuart Colville, graciously released the generator under a BSD license earlier this month.
One of the first articles I wrote about CSS sprites covered the built-in support in GWT, and I focused on their clever trick of including an MD5 checksum of the sprite map contents into the filename. This allows you to set effectively infinite cache headers since the name will change if the underlying image is modified.
I missed covering the release of the YUI Profiler in 2.4.0, but in YUI 2.5.0 they’ve sweetened the pot further with ProfilerViewer Control, a visual interface to the data collected by Profiler. Together, they provide an advanced, cross browser alternative to the profiling features of Firebug, something that is desperately needed as the complexity of client side applications increases. As great as Firebug is at profiling JS, I’m always worried that the data may not perfectly apply to other browsers. With YUI Profiler, that’s not an issue.
The profiling model differs significantly from Firebug, which runs as a browser extension and can reach deep into browser internals for its metrics. YUI Profiler is running within the JS sandbox, so the user is required to register specific functions for profiling. This limits the profiling from broad spectrum analysis of the whole application to more targeted measurement, but that also serves to limit the performance overhead of the profiling itself. When discussing the jsLex approach to instrumentation, I was worried that the tool itself would significantly impact runtime performance; with YUI Profiler, I don’t think that’s a concern.
I’m a fan of this approach. I like targeted instrumentation, and YUI Profiler falls somewhere in the middle between full browser instrumentation (Firebug, jsLex) and granular instrumentation calls (Firebug Lite). There are definitely advantages in the latter approach, such as the ability to measure the time of network events, such as async network calls, which as far as I can tell isn’t possible with YUI Profiler. That might be a nice, easy addition to the suite.
Helsinki CS Masters student Mikko Pervilä has posted his excellent thesis, “Performance of Ajax Applications on Mobile Devices,” for our edification. It’s a fantastically detailed and meticulously cited study, covering everything from the history of Ajax to the performance of current cutting edge mobile devices (including the iPhone and the Nokia N800). He analyzes mobile device performance across Ajax toolkits and large websites, yielding a mixed bag of results. Opera Mobile on the N95 was overall the strongest performer, but I was happy to see my beloved iPhone hold its own.
Also worthy of a read is yet another great Performance Research article by Tenni Theurer on the YUI blog: iPhone Cacheability – Making it Stick. The key takeaways for site designers are that components must be <25kB to be cacheable and the total cache size is only 475-500kB.
Mobile Ajax development is a hot topic, but as these two articles demonstrate, there is still a fair bit of work remaining before mobile devices are as capable as desktop browsers. In the mean time, we need to understand the specific design constraints of our target devices to deliver compelling performance to our users.
Looking back on everything I’ve written here in the past 18 months, one trend is clear: every performance optimization technique I’ve discussed has involved network tweaks or client side scripting. After all, a web developer can typically only control those aspects of the delivered application, so frequently we are looking to trick the browser into behaving a bit more intelligently than it would left to its own devices.
That’s why it’s refreshing to see what the browser vendors working to provide native, and dramatically faster, implementations of some foundational functionality in the Ajax space. Way back in March of 2007, John Resig posted about the native getElementsByClassName in Firefox 3, followed in December by native getElementsByClassName in WebKit. In both cases, the performance improvements over the best JS/DOM implementations were staggering.
More recent is the Safari implementation of the W3C Selectors API and its
querySelectorAll functions. Expect a similar implementation from Firefox in the near future, post 3.0. Conspicuously absent from the discussion is Microsoft, but perhaps we’ll see similar work in IE8.
In general, I think this is great progress for the community, and I like the idea of a formalized process for taking the most successful library functionality and moving it native. There is, however, one point of risk: these native implementations of complex functions will doubtless have the occasional bug, so we may end up in a situation where library vendors need to write messy code to fallback to the JS implementation. For example, if Safari 4.0.1 has a bug involving querying a specific type of CSS selector, every library would potentially need to check the browser version and analyze the input to
querySelector. Enough of those checks, and the performance gains from taking the functions native begin to slip away.
Note: I regrettably missed the Firefox 3 getElementsByClassName in the first version of this post and have attempted to correct the story.