Overview of HTTP/1.1 Waterfall and HTTP/2 multiplexing
Overview
Let's dive deeper into the "waterfall effect" in HTTP/1.1, how it occurs, and how it contrasts with HTTP/2.
Waterfall Effect in HTTP/1.1
In HTTP/1.1, each request-response pair typically uses the following sequence of events over a single connection:
- Step 1: The client sends an HTTP request (e.g., an HTML file).
- Step 2: The server processes the request and sends back a response.
- Step 3: The client parses the response and identifies other resources it needs (e.g., CSS, JavaScript, images).
- Step 4: The client requests these resources one by one, sequentially.
If you look at a browser’s network tab when loading a page using HTTP/1.1, you’ll see the resources being loaded in a sequential manner, with each resource waiting for the previous one to finish. This sequential loading looks like a "waterfall" in the timeline view.
Example Scenario in HTTP/1.1
Imagine a webpage with the following resources:
- An HTML file (index.html)
- A CSS file (styles.css)
- Two JavaScript files (app.js and vendor.js)
- Three images (image1.jpg, image2.jpg, image3.jpg)
In HTTP/1.1, a typical flow might look like this:
-
Request index.html
The client requests the main HTML page from the server.Time: 100ms to download.
The browser can't make further requests until it receives and parses the HTML file to know which other resources are needed.
-
Request styles.css
After receivingindex.html
, the client parses it and discovers thestyles.css
file.Time: 150ms to download.
The browser can't request the next resource until it gets the CSS.
-
Request app.js and vendor.js
Oncestyles.css
is downloaded, the browser can request the JavaScript files.Time: 200ms for
app.js
, 100ms forvendor.js
. -
Request images
After the scripts are processed, the client requests the images sequentially.Time: 100ms for each image.
Each of these requests blocks the next, creating a waterfall effect where each subsequent request has to wait until the prior one completes. Even though the client might be able to open multiple connections (typically 6), the ordering of dependencies (e.g., HTML before CSS, CSS before JS) leads to a serialization of requests.
Head-of-Line Blocking in HTTP/1.1
HTTP/1.1 suffers from head-of-line blocking, meaning that if one request in a sequence takes a long time (e.g., downloading a large image), the following requests are delayed. For example, if one of the images takes 500ms instead of 100ms, all subsequent requests have to wait for that image to finish.
Example Waterfall in HTTP/1.1
Let’s say the following resources have these load times:
index.html
→ 100msstyles.css
→ 150msapp.js
→ 200msvendor.js
→ 100msimage1.jpg
→ 100msimage2.jpg
→ 100msimage3.jpg
→ 100ms
Here’s a simplified representation of the waterfall:
100ms (index.html) --> 150ms (styles.css) --> 200ms (app.js) --> 100ms (vendor.js) --> 100ms (image1) --> 100ms (image2) --> 100ms (image3)
In total, this takes 850ms to load all resources. Each subsequent resource is requested only when the prior one completes.
How HTTP/2 Fixes This
HTTP/2 introduces multiplexing, which allows multiple requests and responses to be sent over a single connection concurrently. This removes the head-of-line blocking and eliminates the waterfall effect.
In HTTP/2:
- The browser can send multiple requests (e.g., for
styles.css
,app.js
, and the images) at the same time without waiting for previous requests to complete. - Each request is split into smaller frames and sent over the same TCP connection, with the server sending responses in parallel.
Example Scenario in HTTP/2
With the same resources as before:
index.html
→ 100msstyles.css
→ 150msapp.js
→ 200msvendor.js
→ 100msimage1.jpg
→ 100msimage2.jpg
→ 100msimage3.jpg
→ 100ms
In HTTP/2, the client can request all of these resources at the same time. The browser doesn’t have to wait for the HTML file to download before requesting the CSS or images.
Here's how the request flow looks in HTTP/2:
index.html --> styles.css, app.js, vendor.js, image1, image2, image3
Even though each resource has different download times, all of them can be requested concurrently. The browser might still have to prioritize certain resources (e.g., HTML before CSS), but the overall time is reduced because multiple resources are being fetched simultaneously.
In this example, the longest resource is app.js
(200ms), so instead of the 850ms it took in HTTP/1.1, the total load time for HTTP/2 would be just 200ms, the time of the longest resource download.
Visualization of HTTP/1.1 vs HTTP/2
- HTTP/1.1:
100ms (HTML)
--> 150ms (CSS)
--> 200ms (JS)
--> 100ms (Images)
- HTTP/2:
Request all resources at once
Total time = 200ms (longest request)
Additional HTTP/2 Features
- Header Compression: HTTP/2 reduces the overhead of sending redundant headers, further improving performance.
- Server Push: The server can proactively push resources (like CSS or JavaScript) to the client without waiting for the client to request them, further reducing latency.
Conclusion
The "waterfall" in HTTP/1.1 occurs due to its sequential, blocking nature when sending requests over a connection. Each request must wait for the previous one to complete before it can be processed, creating cascading delays. HTTP/2 improves this by allowing multiple requests and responses to happen concurrently over the same connection, significantly reducing loading times and eliminating the waterfall effect.
More Articles
Accessing Secure String in Next.js from SSM Parameter Store
Learn how to correctly access secure strings from AWS SSM Parameter Store in a Next.js project, avoiding common pitfalls during the build and deployment phases.
14/08/2024
How to setup a Nextjs 14 custom server
Steps to setup custom Next.js server
24/07/2024
Recommended tsconfig settings For Nextjs 14
Recommended tsconfig settings for Nextjs 14
03/10/2024
CASL Ability Based Http Client to secure NextJS server actions
Explore how to use the AbilityBasedHttpClient class to integrate access control into your API requests using CASL and TypeScript.
08/10/2024