In this blog we analyze the impact of bundling, minification, compression, and pipelining on HTTP performance and in particular the impact on traditional browser scenarios. First we look at the impact of bundling and minification on the content in terms of size. Then we look at the impact of bundling and minification on download and page layout times in a browser-style application.
The purpose is to get a handle on what kind of performance gains can be achieved with a modern HTTP/1.1 implementation when combined with efficient organization of content. The results presented show that only when content and protocol work together is it possible to get significantly faster performance. Just looking at the protocol alone is not sufficient.
In the test evaluated, the speedup was from 638 ms (uncompressed, unbundled, unminified, and not pipelined) down to 146 ms for the equivalent compressed, bundled, minified, and pipelined content. However, by just looking at the data necessary to lay out the page (HTML, CSS, and JS but not images), the time went from 631 ms to 126 ms with the images being finalized within the remaining timespan from 126 to 146 ms.
Thanks to Howard Dierking for help getting the test data and for computing the gains of bundling and minification!
Bundling and minification are two popular (and relatively new) mechanisms for optimizing content used in web pages (see for example these guidelines on saving round trip times (RTT)). Traditionally they focus on optimizing CSS and JS resources but there is no inherent limitation in the general model that prevents it from being used on other content. In this experiment we only looked at saving with respect to CSS and JS but future work could include looking at other content as well.
The general idea behind bundling is to concatenate multiple files of the same type into a single file hence getting a single large resource rather than a number of small resources. Minification takes bundling one step further by adding model-based compression to the content. In addition to removing white space, minification typically shortens variable names and other identifiers and removes pieces that are not used.
Bundled and minified content is a resource like any other resource with a URI so no modification of the client side is needed to accommodate bundling or minification. Further, these resources are fully cachable and can be compressed like any other content.
The bundling and minification we use in this experiment is shipping with ASP.NET 4.5. However, there is nothing particular about that implementation compared to other alternatives and so we think it is possible to get similar benefits from other implementations.
Compression algorithms like GZip and Deflate are commonly used in HTTP and so we have compared compression with bundling and minification. Note that the two are not mutually exclusive; in fact our data shows that compression works better on a bundled document due to the larger size and hence the opportunity for better compression ratio. For example, for one of the web pages tested with 7 JS and 6 CSS resources, the results of compressing the individual resources vs. compressing the minified bundles were as follows:
Similarly for CSS:
While not something we have investigated, one can imagine that minification also reduces the time it takes to parse the content as there is less data that has to be parsed.
In addition to the bytes saved in the content, it also saves HTTP overhead in going from 7 to 1 request for JS and 6 to 1 for CSS. This, as we shall see, makes other significant savings possible due to network implications of being able to retrieve the entire bundle in a single request.
We first looked at data from the following web site home pages to get the difference in size by bundling and minifying the CSS and JS files referenced from those pages. We only looked at CSS and JS coming from the same DNS domain (i.e. for digg.com we looked at anything under *.digg.com. The result is listed below where the last three columns illustrate the percentage saved in terms of bytes and the requests saved by bundling all the CSS into one file and all the JS into another.
The data shows significant savings in terms of size of CSS and JS as well as number of requests executed. This bundling algorithm may not work in all cases but it should be possible to limit the number of bundles to less than a handful and typically it would be one or two.
js size (kb)
css size (kb)
image size (kb)
css bundle size (kb)
css minified size (kb)
js bundle size (kb)
js minified size (kb)
In addition to comparing the bundled and minified content with the original content we ran a set of download experiments to evaluate the impact on the HTTP performance and rendering time within a browser. For this experiment we only looked at huffingtonpost.com which we re-created as a local copy so that we could work with the data without it changing under us as the web site gets updated.
A critical part of being able to measure performance of a web page is the time it takes to layout the page which may be shorter than the time it takes to download the entire content. With modern uses of HTML, there are typically three parts that needs to be downloaded in order for the content to be rendered:
Other content such as images are typically not critical for the layout to be completed and can be filled out as data is being downloaded. To get a measure for how quickly a page may be rendered we measured the download time for each of four groups of content: HTML, CSS, JS, and images. We could then determine when the entire content was downloaded vs. when the HTML, CSS, and JS (but not images) were downloaded.
In the download data presented below we look at both pipelined GET requests and non-pipelined requests (but with persistent TCP connections). In the setup we used (100MBit wireless Ethernet) and even though the RTTs in this environment are very small we did notice a difference between pipelined and non-pipelined requests. However, in any networking environment with larger RTTs being able to submit requests without waiting for a response becomes a necessity. As has been most recently documented in Mark Nottingham’s IETF draft "Making HTTP Pipelining Usable on the Open Web”, there are known problems with practical deployment if pipelining in open network environments. However, it is clear that in order to achieve the best possible performance where RTTs is a factor, it is required to eliminate RTTs aggressively and pipelining can help doing that.
The first table shows the total download time for each of the four content categories starting from the point where the first resource (i.e. the HTML page) is requested. That is, the values indicate the times it took to complete the download of all the HTML, CSS, JS, and images respectively counting from the beginning of the very first request asking for the HTML. This means that not all the time is actually used downloading as the CSS, JS, and images only can be initiated once the HTML is being downloaded and links are identified. The times do not include DNS lookups as we used literal IP addresses to connect to the server.
The first thing that is apparent is that the download time shrinks from left to right in the table with plain being the slowest with a total download time of 638 ms and GZip compressed, pipelined, bundled, and minified being the fastest with a total download time of 146 ms for the same web page. However, there is more to the data than just the total download time. In the section on page layout we described how getting the HTML, CSS, and JS was critical to laying out the page.
To better being able to interpret the data we represent it in a set of graphs where the Y axis is total download time in ms for the content of a particular category. Looking at the plain data column, it is apparent that the HTML is done after 264 ms but neither the CSS nor the JS is anywhere near done. In fact, the last parts of the CSS, JS, and images all end roughly at the same time (622, 631, and 638 ms respectively).
Below are similar graphs for the other four columns above but we have adjusted the scale of the Y axis to more easily see the differences in detail. Looking at the compressed data, it is clear that even though the download is much faster than plain data, downloading the CSS and JS still takes almost as long as downloading the images (162, 175, and 179 ms respectively). That is, compression does not reorganize the order in which links are referenced within the HTML and hence it is still possible to see a significant delay before the page can be rendered.
Turning on HTTP/1.1 pipelining further lowers the total download time, but just like compression, does not alter the location of the links in the HTML, leading to similar data as for compression. That is, the JS is not completely downloaded until the images also have been downloaded (146 vs. 150 ms). The important thing to note here is that without deliberate organization of the content, there is little the protocol can do to optimize the performance. Only when content and protocol work together is it possible to get significantly faster performance.
With bundling and minification, the picture starts to look different for two reasons: First, the links to the CSS and JS have been put all the way at the top of the HTML so that it the client parser gets to the links very fast and can submit them to the server. In the original content, the first CSS link was found at byte offset 2213 within the HTML and the first JS link was found at byte offset 3730. By moving these links to the very beginning they could be initiated earlier.
Second, with the fewer requests there is also less protocol overhead and less interruption of parsing the data. The result is that the CSS and JS are completely downloaded after 135 ms, allowing the page to be rendered while the remaining images are still being loaded.
Lastly, we tried the full suite of compressed, pipelined, bundled, and minified content. Even with the low RTT we did observe a difference in lower times to download the content and it produced the fastest time of 146 for downloading the images and only 126 to download the JS and hence being able to layout the page,
Bundling and minification can result in significant savings in terms of bytes to exchange and requests necessary to execute and hence lead to faster page render times. In addition, by applying compression and pipelining to bundling and minification it is possible to get significant speedup in the time it takes to download the HTML, CSS and JS for laying out a page, especially by putting the links to the bundled and minified CSS and JS at the very top of the HTML. In short, only when content and protocol work together is it possible to get significantly faster performance. Just looking at the protocol alone is not sufficient.
In the test evaluated, the speedup was from 638 ms in plain mode down to 146 ms for the equivalent compressed, pipelined, bundled and minified content. However, by just looking at the data necessary to lay out the page (HTML, CSS, and JS but not images), the time went from 631 ms to 126 ms with the images being finalized within the remaining timespan from 126 to 146 ms.
Here’s a short list of the possible optimizations that we observed:
These parts will in combination with an efficient browser implementation leveraging compression and pipelining provide a much faster rendering time.