Server-sent events
A page usually answers once. With padSse() in its PHP it keeps the connection open and sends events while they happen - what the browser's EventSource reads, and what htmx's sse extension, a React or an Alpine component listen to. There is no template: the stream is the whole answer.
<?php
// ticker.php - the producer sends the events itself
padSse ( function ( $send, $lastId ) {
foreach ( [ 'one', 'two', 'three' ] as $n => $word ) {
$send ( 'word', [ 'n' => $n, 'word' => $word ], $n );
sleep ( 1 );
}
}, [ 'retry' => 3000 ] );
?>
The browser side is a few lines, with no library:
const source = new EventSource('?ticker');
source.addEventListener('word', event => show(JSON.parse(event.data)));
On an interval
Given every, PAD calls the producer itself, every so many seconds, and sends what it answers as the event named by event: an array goes as JSON, NULL sends nothing that round, FALSE ends the stream.
<?php
// stats.php - a fresh number every two seconds, for at most a minute
padSse ( fn () => [ 'orders' => db ( "FIELD count(*) FROM orders" ) ],
[ 'every' => 2, 'for' => 60, 'event' => 'stats' ] );
?>
| Option | Meaning |
|---|---|
every
|
Seconds between two calls of the producer; without it the producer is called once and loops itself |
for
|
How long a stream with every runs at most - 60 seconds unless said otherwise
|
event
|
The name of the event an answer of the producer is sent as - message unless said otherwise
|
retry
|
Milliseconds the browser waits before it reconnects when the stream ended |
What to know
-
$send ( $event, $data, $id )answers whether the visitor is still connected; a long loop stops when it says no. Text data that runs over lines goes as severaldata:lines, which the browser joins again. - An event needs data: the browser drops one whose data is empty, so an event a page closes the stream on says something -
$send ( 'done', 'done' ). - The browser reconnects by itself and sends the id of the last event it had - the producer gets it as its second argument,
padSseLastId()reads it anywhere. - The session is written and closed before the first event, so the visitor's other requests do not wait for the stream; read what the producer needs from it first.
- A stream holds a PHP worker for as long as it runs: keep
forshort and let the browser reconnect. Nothing of the answer is cached, compressed or buffered by PAD;X-Accel-Buffering: noasks nginx not to hold the events back. - In the browser - an application packed by
pad pack, see Offline applications - one PHP answers the whole tab, so a stream is one round there: theeveryform calls its producer once and asks the browser back after the interval, aFALSEwith nothing sent is answered 204 and ends it, and the loop form ends at the first event sent a tenth of a second after it began.padWasm()says where a page runs.
The htmx application streams rows of HTML that its sse extension swaps in (htmx/?examples/live), the Alpine application JSON an EventSource turns into state (alpine/?examples/live).