HTTP/1.1 and HTTP/2 Streaming Techniques
An overview of web streaming technologies, from HTTP/1.1 to modern approaches like HTTP/2 Streams API and Shadow DOM.
Dictionary
Multiplexing - Multiple streams on a single connection.
Bidirectional - A connection where both endpoints can send and receive data. Example: web chat.
Unidirectional - A connection where one endpoint can only send data and the other endpoint can only receive data. Example: notifications.
Half-duplex - A bidirectional connection that can send and receive data, but not both at the same time. One after another.
Full-duplex - A bidirectional connection that can send and receive data at the same time.
HTTP/1.1 vs HTTP/2 Streaming
Chunked transfer encoding (CTE) is an old way (HTTP/1.1) of streaming data from the server to the client. It probably doesn't work in HTTP/2 very well or at all. One feature of it is that it's easy to remember because it has the same acronym as the brain damage you get from boxing (Chronic Traumatic Encephalopathy).
Here's an example of receiving chunks on the client:
The HTTP/2 Streams API is a new API for bidirectional streaming of data. The easiest way to test it out is with Fetch API. It also seems to be backwards compatible with CTE.
I am not sure about the support of streaming from client to the server with Fetch API. But it's definetely possible in Chrome since Chromium 105.
As you can see in the comment above, the connection is half-duplex, so if you're interested in full-duplex communication between client and server, there's a HTTP/3 W3C WebTransport API that you might find interesting. I haven't read much about it; it seems useless for my use cases.
When it comes to receiving data on the client from the server, it's well supported in all modern browsers and works with the Fetch API in the same way as chunked transfer encoding worked, so no API changes are needed.
Next.js handles its fancy streaming feature in a similar way. They use the renderToReadableStream
function from react-dom/server
and simply stream it to the client, which then reads the chunks and hydrates them asynchronously.
Server-Sent Events (SSE)
SSE allows for unidirectional streaming, from the server to the client. The biggest issue with SSE was that it is limited to the browser's maximum number of allowed connections. Connections were not shared between tabs, meaning that every new tab with an SSE client would create a new connection. The limits ranged from 4 (in Chrome) to even up to 10 in some other browsers.
Especially in mobile devices - when they have battery-saving mode enabled, they reduce the number of connections by a lot. From what I've read, it is no longer an issue with HTTP/2 because they have up to 100 connections (or streams) per domain - not sure if that also applies to mobile devices.
Here's an example of a simple SSE client:
The API is quite simple, much simpler than WebSockets, but also much more limited and only unidirectional. You get messages in string form, but backends often use JSON for the payload.
One thing that I also love about SSE and something that is lacking in other streaming solutions is DevTools. When the request has content type text/event-stream
, Chrome DevTools will display an additional tab where you can preview all the messages sent.
Streaming without JavaScript with Shadow DOM
I've been thinking about whether it's possible to stream data without JavaScript. It seems impossible since we need some kind of JavaScript client to "receive" those chunks of data. But I was wrong. There's this thing called Shadow DOM and Declarative Shadow DOM that makes it possible to create Shadow DOM on the server, and the browser will render it without JavaScript by using a new shadowrootmode
attribute on a <template>
tag.
Why is it such a big deal? Streaming is an easy and comfortable way to achieve progressive enhancement, improve web performance, and ultimately enhance SEO. However, the fact that we need JavaScript to do this makes it slower and possibly worse for SEO, since bots would need more time to render the page, and there is a higher chance that not all content will be crawled.
Here's a blog post that explains it in more detail: Streaming HTML out of order without JavaScript
and here's a demo of it in action: https://ooo.lamplightdev.workers.dev/
WebSockets (WS)
WebSockets use HTTP only for a handshake, and then the WS protocol is used, so they don't apply to this article.
Published on July 30, 2024 • 5 min read