- Network transfer time – the time it takes to receive the resource after the browser has requested it.
- Resource preparation time – the time it takes to prepare the resource for use.
- Source code parse time – the time it takes to parse the resource into something useful.
- Execution time – the time it takes to apply the resource to the page. Already talked about at length on this blog.
As this issue became better understood, browsers started implementing true decompression solutions so that servers could use real compression, not just byte reduction, to transfer resources. The two commonly supported compression schemes are gzip and deflate, supported by all major browsers as well as server software. Generally, these gzip and deflate work in the same manner. A basic description of gzip (source):
The deflation algorithm used by gzip (also zip and zlib) is a variation of LZ77 (Lempel-Ziv 1977, see reference below). It finds duplicated strings in the input data. The second occurrence of a string is replaced by a pointer to the previous string, in the form of a pair (distance, length). Distances are limited to 32K bytes, and lengths are limited to 258 bytes. When a string does not occur anywhere in the previous 32K bytes, it is emitted as a sequence of literal bytes. (In this description, ‘string’ must be taken as an arbitrary sequence of bytes, and is not restricted to printable characters.)
Compressing resources using gzip or deflate makes resource files as small as possible during network transfer. However, doing so introduces a second point of interest: resource preparation time.
The browser must decompress any compressed resources before using them and I call this resource preparation time. You’ve saved network transfer time but introduced an additional step before the browser can make use of the file. Thankfully, decompression tends to be fast in modern browsers and doesn’t cause any issues (older browsers such as Internet Explorer 5 had issues when decompressing certain files). Still, I count this as part of the process.
Though it seems like a lot of people enjoyed the presentation, there were a subset who did not. Of those dissenters, there were two basic concerns:
- Doing everything I suggested can actually increase the compressed file size.
- Performance overhead of declaring variables to use instead of literal values for
To address the first point, I pointed out earlier that gzip works by looking for repeating string patterns and replacing them with pointers. By storing repeated literal values in variables you are, effectively, removing gzip’s most effective weapon. Naturally, this can affect the overall compressed size of your file.
I decided to put this to a really simple test and used the
toggle() function from the presentation as an example. I ran the YUI Compressor and gzip on both the original version and the optimized version.
<th> Raw </th> <th> Minified </th> <th> Gzipped </th> <th> Both </th>
<td> 263 </td> <td> 172 </td> <td> 161 </td> <td> 140 </td>
<td> 327 </td> <td> 127 </td> <td> 194 </td> <td> 144 </td>
As you can see, when using both the YUI Compressor and gzip on the source, the original actually comes out smaller than the optimized version. The difference may be small, but we’re talking about a fairly small code sample as well. You can assume that code optimized with the techniques in my presentation will be a small percentage larger when minified and gzipped versus the originals.
Given this difference, the only performance reason to apply all of the techniques in the presentation would be if there’s a value in having the smallest-possible minified but not compressed file size. My theory about this size affecting parse time will have to be proved (or perhaps disproved), but there are other reasons why minified file size is important.
The Yahoo! Exceptional Performance team did some research on browser caching and found that Safari for the iPhone caches the uncompressed version of the files. Further, the maximum file size cached by Mobile Safari is 25 KB. In this case, both the wire weight and the disk weight are important for performance reasons as you clearly don’t want to re-download resources on your iPhone if not necessary. Indeed, Ryan Grove of Yahoo! Search did a writeup on how he used these techniques to optimize Yahoo! Search for the iPhone.
There probably is a balancing point where applying some of these techniques, but not all, would result in the smallest possible file size and I’ll continue to research to see if there’s a way to optimize in that direction.
This is the classic performance optimization struggle of space vs. time. If this approach results in smaller file size and therefore faster network transfer time and parse time, are you willing to take a small execution time performance hit? That’s not a question I can answer for you or anyone else, it’s a tradeoff you have to ask yourself if you’re willing to make. It’s impossible to get the fastest executing code and the smallest, so there’s a balancing point that you as the developer need to make a decision on.
Which techniques to use