📜 ⬆️ ⬇️

HTTP / 2 is already here but sprite sets are not dead yet.

In this study, we show that even if the new HTTP / 2 protocol significantly improves page loading speed, the time to completely abandon front-end optimizations has not yet come. Today we will focus on sprite sets.


HTTP / 2 became available in 2015 as an alternative to replacing the highly respected HTTP / 1.1 used since 1997. Many authors predict the obsolescence or even the counterproductiveness of front-end optimizations. The list of classic optimizations includes sprites: grouping many small images (sprites) into one large (sprite set).

Despite the rapid introduction of support in browsers and servers ( wikis , w3techs ), we could not find published comparative measurements to confirm the statement (note that sprites are no longer needed) . As web architects, then, naturally, we were interested in whether we should abandon the approach of sprites or not. As William Edwards Deming's famous quote reads: “In God we trust, all others bring data”. Therefore, we made our own benchmark.


The first part of this article describes the main differences between HTTP / 1.x and 2 and why they may contribute to the obsolescence of sprites. In the second part, we will show the comparative results of the benchmark.


Sprite Sets


Sprite sets are front-end optimization . Instead of downloading several images from the server one at a time (for example, a set of icons that are used across the page), one sprite set is loaded once and later, each sprite can be cut . The sprite set used in our benchmark from www.facebook.com is shown in Fig. one.



Fig. 1: benchmark sprite set.


This sprite set is composed of 72 sprites that can be accurately cut into small individual images of each sprite.


The first thing that catches your eye is that the sprite set as a single global image weighs only 71 kB, while the sprites, as separate images, total 106 kB, are almost 40% more. The combined size is smaller than the sum due to better image compression and reduced redundant image headers. Moreover, one request to the server is enough to load all the icons of the site with the sprite-set , instead of a set of requests, one for each image.


In order to draw pictures in the browser, the sprite set is cut into small icons in the CSS code . In Fig. 2 you can see the HTML used with / without the use of sprites, and the corresponding CSS styles. The resulting load is also displayed on the graph.


CSS with separate imagesHTML (common)CSS with sprite set
div.sprite-icons { background-repeat: no-repeat; } div.sprite-icons-pause { background-image: url('icon-pause.png'); width: 60px; height: 60px; } ... 
 <div class="sprite-icons sprite-icons-pause"> </div> <div class="sprite-icons sprite-icons-pause-disabled"> </div> <div class="sprite-icons sprite-icons-play"> </div> 
 div.sprite-icons { background-image: url('icons.png'); background-repeat: no-repeat; } div.sprite-icons-pause { background-position: 0 -60px; width: 60px; height: 60px; } ... 


Fig. 2: with / without the use of sprite sets.
Two images capture HTTP requests. Without a sprite set, you can see several parallel small requests with a total higher completion time.


Obviously, the CSS code is much simpler without the sprite set, but the load time is much shorter with the use of sprites . When using sprite-sets several technical overlays arise, they will be discussed below.


The main limitations of the sprite set approach are:



HTTP / 1.x and sprites


In HTTP / 1.x, no more than one request (note at the same time) is possible within one TCP connection between the client and the server. The following requests must wait in queue in order to reuse the TCP connection. In order to reduce download time and to avoid page freezes due to one long request, modern browsers open several parallel TCP connections to the server (usually, from 2 to 8 connections, depending on the browser ). Nevertheless, such parallelization is limited and the use of a large number of requests still means that the load time will be longer, and the network is overloaded, even without taking into account the back-end.


Uploading all independent images at a time results in multiple requests in HTTP / 1.x and greatly influences the final download time, hence the UX, while using a sprite set will result in one request, which is a huge optimization on many web sites. -sites.


HTTP / 2 and sprites


With HTTP / 2, all requests between the browser and the server are multiplexed (compressed) into one TCP connection .
By offsetting the cost of opening and closing multiple connections, this leads to a better use of the TCP connection and limits the effect on latency between the client and the server.


This allows you to load dozens of images in parallel in a single TCP connection. As a result, using sprite sets to reduce the number of requests may become useless. All these sentences (note of the phrase) are still hypotheses: this article will show how reality differs from theory.


Benchmarking methodology


All code for repeating this benchmark is available on Github .


To reproduce various situations, six HTML pages were created. The first of them uses the sprite set, the rest, include various amounts of individual images.


Setup NameImagesQty
Singlesprite set100% (72)
AllSplittedseparate100%
80pSplittedseparate80%
50pSplittedseparate50%
30pSplittedseparatethirty%
10pSplittedseparateten%

The last four pages, with only part of the sprites, show the most common situation when all the sprites are not used simultaneously: only part of the images are needed, depending on the context (language, geolocation, application status, etc.). Using separate images instead of sprite sets allows you to download only those that are needed from the entire collection. However, the results will demonstrate how the grouping remains effective.


In our benchmark, JavaScript code was developed to calculate the time interval between the end of loading the HTML page (script execution in the page header) and the loading of the last image (the last onload ). This time interval is calculated and recorded for each case. Pages and images were uploaded to two NGINX 1.9.5 servers located in one data center on two identical virtual machines.


One server supports HTTP / 2, while the other supports only HTTP / 1.1. Pages are requested via HTTPS , even with HTTP / 1.1, in order for the comparison to be as honest as possible with respect to HTTP / 2 which only supports secure transmission.


On the client side, a Python script was developed to request pages via two browsers, Firefox 41.0 and Chrome 45.0 (approx. Current versions at the time of this writing) , launched via Selenium WebDriver . Selenium allows you to have a new browser context for each request to avoid the effect of caching. Of course, if the images were cached by the browser, we would not be able to test the protocol since there would be no real transfer (only an empty body with code 304). Selenium also allows you to simply check the DOM to get a time gap calculated by JavaScript and displayed on the page.



Fig. 3: test code architecture.


In order to obtain reliable results, the protocol is run a hundred times for each case , as shown in the pseudocode below.


 for i = 1 to 100 for page in ('Single', 'AllSplitted', '80pSplitted', '50pSplitted', '30pSplitted', '10pSplitted') for protocol in ('HTTP/1.1', 'HTTP/2') for browser in ('Firefox', 'Chrome') #load page and measure load time 

For each case , the median value is recorded . If you look at the distribution of time for one case (see Fig. 4), we observe sharply distinguished values ​​due to the initially stochastic (approx. Random) process of the network. The influence of these points on the average value will be great. On the other hand, the median is a reliable indicator since the distribution is almost uniform.



Fig. 4: the initial data load time, when you repeat the calculation a hundred times.


To expand the scope of current situations, the protocol was repeated on three client configurations :


configurationdescriptionaverage delaydownload capacity
#oneVM in a good datacenter10ms80Mb / s
# 2laptop with good internet connection40ms20Mb / s
# 3laptop with bad internet connection35ms1.3Mb / s

Benchmark results


Three configurations yielded very coherent (approx. Logically followed) results shown in Fig. five.



Fig. 5: total load medians for different types of pages, browsers, http protocols and network configurations.


The graphs show that:



For further analysis of these results, you can also map the median load time in relation to the number of requests or the sum of the image sizes. Fig. 6 shows the results for the above configuration # 3.




Fig. 6: The same experiments as in Fig. 5, with configuration # 3, but comparing the dependence of time to the number of images and the sum of the sizes of the images.


Based on these two graphs, it is possible to judge that the approach of the sprite sets is very different from the individual sprites due to the use of one query , while the total size is the second in terms of its effect on speed.


Conclusion


This benchmark clearly advocates that the optimization of sprite sets is still relevant, even after upgrading to the HTTP / 2 protocol . Even though the new protocol offers a significant improvement in load time (up to 50%) compared to HTTP / 1.1, this may not be enough. If HTTP / 2 optimizes the use of the network, this will not be a reason for completely abandoning front-end optimizations , including sprite sets, CSS / JS minification, and bundles .


Note translator: the article has some outdated data due to the release date of the article (December 2015), but the main message remains relevant.


')

Source: https://habr.com/ru/post/308862/


All Articles