How Streaming Output and Reactive Programming Boost Web Performance
This article explains the concepts of streaming output and reactive programming, describes the underlying HTTP chunked transfer, SSE, WebSocket and RSocket protocols, provides code examples, and outlines practical scenarios where end‑to‑end streaming improves performance and user experience.
Terminology
Stream (or streaming) is an asynchronous data‑flow framework used across many technology stacks: React.js and RxJS on the front‑end, RxJava and Reactor on the server, and RxJava on Android. It forms the basis of reactive programming.
Reactive / Reactive Programming
Reactive programming treats the result of a previous task as an event that triggers the next task. The component that receives and emits events is called a Reactor . A simple reactive model diagram is shown below:
Streaming Output
Streaming output splits a page into independent modules, each with its own data source and template. The server processes each module and streams the rendered HTML chunks to the client, which renders them progressively. The same principle applies to JSON data streams.
End‑to‑End Reactive
Beyond client‑server streaming, micro‑services can also exchange data streams, enabling end‑to‑end reactive architectures.
Theoretical Foundations
1. HTTP Chunked Transfer Encoding
Chunked transfer encoding (available in HTTP/1.1) allows a response to be sent in a series of chunks. The server sets Transfer-Encoding: chunked in the response header. Example format:
HTTP/1.1 200 OK
Transfer-Encoding: chunked
...
<chunked 1 length>
<chunked 1 content>
<chunked 2 length>
<chunked 2 content>
...
0Go example handling a chunked response:
func handleChunkedHttpResp(conn net.Conn) {
buffer := make([]byte, 1024)
n, err := conn.Read(buffer)
if err != nil {
log.Fatalln(err)
}
fmt.Println(n, string(buffer))
conn.Write([]byte("HTTP/1.1 200 OK
"))
conn.Write([]byte("Transfer-Encoding: chunked
"))
conn.Write([]byte("
"))
conn.Write([]byte("6
"))
conn.Write([]byte("hello,
"))
conn.Write([]byte("8
"))
conn.Write([]byte("chunked!
"))
conn.Write([]byte("0
"))
conn.Write([]byte("
"))
}2. HTTP Server‑Sent Events (SSE)
SSE is a standard HTTP protocol for unidirectional event streams from server to client. It supports automatic reconnection and custom event types. Key fields:
event : name of the event type.
data : payload; multiple data lines are concatenated.
id : last‑event‑id for reconnection.
retry : reconnection delay in milliseconds.
Client example (JavaScript):
// Initialize EventSource
const evtSource = new EventSource("//api.example.com/ssedemo.php", { withCredentials: true });
// Listen for messages
evtSource.onmessage = function(event) {
const newElement = document.createElement("li");
const eventList = document.getElementById("list");
newElement.innerHTML = "message: " + event.data;
eventList.appendChild(newElement);
};Server example (PHP):
date_default_timezone_set("America/New_York");
header("Cache-Control: no-cache");
header("Content-Type: text/event-stream");
$counter = rand(1, 10);
while (true) {
echo "event: ping
";
$curDate = date(DATE_ISO8601);
echo 'data: {"time": "' . $curDate . '"}';
echo "
";
$counter--;
if (!$counter) {
echo 'data: This is a message at time ' . $curDate . "
";
$counter = rand(1, 10);
}
ob_end_flush();
flush();
sleep(1);
}3. WebSocket
WebSocket provides full‑duplex communication over a single TCP connection, offering higher flexibility but requiring more code intrusion compared to SSE.
4. RSocket
RSocket is a reactive application protocol that works over TCP, WebSocket, or Aeron. It supports binary framing, back‑pressure, and four interaction models, making it suitable for micro‑service communication.
Simple Java RSocket server/client example:
import io.rsocket.AbstractRSocket;
import io.rsocket.Payload;
import io.rsocket.RSocket;
import io.rsocket.RSocketFactory;
import io.rsocket.transport.netty.client.TcpClientTransport;
import io.rsocket.transport.netty.server.TcpServerTransport;
import io.rsocket.util.DefaultPayload;
import reactor.core.publisher.Mono;
public class RequestResponseExample {
public static void main(String[] args) {
RSocketFactory.receive()
.acceptor(((setup, sendingSocket) -> Mono.just(
new AbstractRSocket() {
@Override
public Mono<Payload> requestResponse(Payload payload) {
return Mono.just(DefaultPayload.create("ECHO >> " + payload.getDataUtf8()));
}
}
))
.transport(TcpServerTransport.create("localhost", 7000))
.start()
.subscribe();
RSocket socket = RSocketFactory.connect()
.transport(TcpClientTransport.create("localhost", 7000))
.start()
.block();
socket.requestResponse(DefaultPayload.create("hello"))
.map(Payload::getDataUtf8)
.doOnNext(System.out::println)
.block();
socket.dispose();
}
}5. Reactive Programming Frameworks
Reactive frameworks (e.g., RxJava, Reactor, Spring WebFlux) enable end‑to‑end asynchronous data streams, fundamentally changing development models.
Example using RxJava:
@Override
public Single<Integer> remaining() {
return Flowable.fromIterable(LotteryEnum.EFFECTIVE_LOTTERY_TYPE_LIST)
.flatMap(lotteryType -> tairMCReactive.get(generateLotteryKey(lotteryType)))
.filter(Result::isSuccess)
.filter(result -> !ResultCode.DATANOTEXSITS.equals(result.getRc()))
.map(result -> (Integer) result.getValue().getValue())
.reduce((acc, lotteryRemaining) -> acc + lotteryRemaining)
.toSingle(0);
}Application Scenarios
1. Page Streaming
Dynamic pages benefit from splitting HTML into modules (e.g., head vs. body) so the browser can start rendering while later modules are still being generated, improving TTFB, CSS/JS load time, and overall perceived performance.
2. Data Streaming
Large JSON payloads can be streamed via SSE, reducing latency and CPU usage compared to a single massive response. Dependent interfaces can also be streamed sequentially to avoid waiting for upstream data.
Conclusion
Streaming output originated from server‑side rendering and now forms the backbone of end‑to‑end reactive architectures, offering performance gains at the cost of increased operational complexity.
Various protocols (HTTP chunked, SSE, WebSocket, RSocket) and reactive frameworks provide flexible solutions for different scenarios.
Choosing the right streaming strategy and module granularity can significantly improve page load times and data delivery efficiency.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Alibaba Cloud Developer
Alibaba's official tech channel, featuring all of its technology innovations.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
