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.

Alibaba Cloud Developer
Alibaba Cloud Developer
Alibaba Cloud Developer
How Streaming Output and Reactive Programming Boost Web Performance

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:

Reactive model diagram
Reactive model diagram

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.

HTML streaming flow
HTML streaming flow

End‑to‑End Reactive

Beyond client‑server streaming, micro‑services can also exchange data streams, enabling end‑to‑end reactive architectures.

Micro‑service streaming
Micro‑service streaming
Full request‑response chain streaming
Full request‑response chain streaming

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>
...
0

Go 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.

RSocket architecture
RSocket architecture

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.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

BackendStreamingreactive-programmingSSErsocketHTTP Chunked Transfer
Alibaba Cloud Developer
Written by

Alibaba Cloud Developer

Alibaba's official tech channel, featuring all of its technology innovations.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.