HTTP/2 leaves the basic concepts of Requests, Responses and Headers intact. Changes are mostly at the transport level, improving the performance of parallel requests – with few changes to your application. The go HTTP/2 ‘gophertiles’ demo nicely demonstrates this effect.

A new concept in HTTP/2 is Server Push, which allows the server to speculatively start sending resources to the client. This can potentially speed up initial page load times: the browser doesn’t have to parse the HTML page and find out which other resources to load, instead the server can start sending them immediately.

This article will demonstrate how Server Push affects the load time of the ‘gophertiles’.

HTTP/2 in a nutshell

The key characteristic of HTTP/2 is that all requests for a server are sent over one TCP connection, and responses can come in parallel over that connection.

Using only one connection reduces overhead caused by TCP and TLS handshakes. Allowing responses to be sent in parallel is an improvement over HTTP/1.1 pipelining, which only allows requests to be served sequentially.

Additionally, because all requests are sent over one connection, there is a Header Compression mechanism that reduces the bandwidth needed for headers that previously would have had to be repeated for each request.

Server Push

Server Push allows the server to preemptively send a ‘request promise’ and an accompanying response to the client.

The most obvious use case for this technology is sending resources like images, CSS and JavaScript along with the page that includes them. Traditionally, the browser would have to first fetch the HTML, parse it, and then make subsequent requests for other resources. As the server can fairly accurately predict which resources a client will need, with Server Push it does not have to wait for those requests and can begin sending the resources immediately.

With server push enabled, you will see that after the DOM has loaded, the images are almost immediately there, because they have been Push’ed already.

All that glitters, however, is not gold: as you will notice when experimenting (especially at lower artificial latencies), while Server Push fairly reliably reduces the complete load time, it sometimes increases the time until the DOM-content is loaded. While this makes sense (the browser needs to process frames relating to the Server Push’ed resources), this could have an impact on the perceived performance of your page: for example, it could delay running JavaScript code embedded in your site.

HTTP/2 does give you tools to tune this, such as Stream Priorities, but this might need careful tuning and be supported by the http2 library you are choosing.

Conclusions

HTTP/2 is here today, and can provide a considerable improvement in perceived performance – even with few changes in your application.

Server Push potentially allows you to improve your page loading times even further, but requires careful analysis and tuning – otherwise it might even have an adverse effect.

Shares

Previous post

Next post

Comments

thank you for the article. so, there might be a situation where server push is configured to for important.js and superimportant.css, yet those files are already in the browser’s cache… wouldn’t that be an excessive push? or there is a conditional push (similar to conditional GET in HTTP/1.1)?

Your observation that a push with a resource that is already in the cache might be excessive is accurate – as mentioned at the end of that paragraph, the client can cancel the push, but some bandwidth might already have been wasted.

I’m not aware of something like ‘conditional push’ in the protocol. Indeed you could use server push to tell the client the latest etag/modification date for some resource, and then let the client decide whether it needs to do another request.

That problem was solved by Kazuho Oku through clever use of cookies and something he calls cache digests. You can find the technique somewhere in his blog, and it is currently being discussed to be converted in a standard. It is also used by ShimmerCat.

I do not understand why Server Push would delay the DOMContentLoaded event. Does the browser not still conform to firing DOMContentLoaded after all static content loads? And doesn’t multiplexing reduce the load time? The only scenario I can imagine DOMContentLoaded getting delayed is if Server Push is pushing several dynamic resources ahead of DOMContentLoaded. Can you explain this scenario a bit more?

Exactly – DOMContentLoaded fires when all the static tags (DOM) has loaded. If there’s any static script tags at the end of the page, it will fire once those scripts are loaded. As you mentioned, resources such as images do not need to be there. However, with CSS, if there is ANY static script tag that comes after a CSS link tag, the DOMContentLoaded will wait until BOTH the CSS and the JavaScript load. However, if you dynamically insert a script tag via JavaScript, this will not affect DOMContentLoaded.
I will check out your links, but still do not understand what the scenario is to cause DOMContentLoaded to be delayed over HTTP/2, unless it is delivering dynamic content ahead of (or in parallel with) the static content.