Something went wrong. Try again.
Demo comparing html-over-the-wire w/ WS and SSE.
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124// Test 2 — the number that actually matters: user clicks -> patched HTML lands.//// Measured client-side, end to end: t0 is the dispatch call, t1 is the arrival// of the patch carrying that command's nonce on the client's own stream. This// is identical work for both architectures.//// Reported separately: the FIRST command after connect (where a cold HTTP/1.1// socket must handshake) vs steady state (where it must not). That split is// precisely the article's "avoids repeating the TCP handshake" claim.
import { startServer, startProxy, sleep, summarize, table } from './lib.js'import { createClient } from '../src/client.js'
const CLIENTS = Number(process.env.CLIENTS ?? 100)const ROUNDS = Number(process.env.ROUNDS ?? 30)const THINK_MS = Number(process.env.THINK_MS ?? 25)const RTTS = (process.env.RTTS ?? '0,25,100').split(',').map(Number)
const VARIANTS = [ { name: 'ws', arch: 'ws', tls: true }, { name: 'sse+POST h2', arch: 'sse', tls: true }, { name: 'sse+POST h1', arch: 'sse', tls: true, h1: true },]
const results = []
for (const rtt of RTTS) { for (const v of VARIANTS) { const server = await startServer({ ...v, compress: 'none', mode: 'narrow' }) const proxy = await startProxy({ targetPort: server.port, owdMs: rtt / 2 }) await sleep(200)
const clients = [] const connectSamples = [] for (let i = 0; i < CLIENTS; i++) { const c = createClient({ arch: v.arch, h1: v.h1, host: '127.0.0.1', port: proxy.port, tls: v.tls, room: String(i), compress: 'none', }) const t0 = performance.now() await c.connect() connectSamples.push(performance.now() - t0) clients.push(c) }
// pending nonce -> resolver, per client const first = [] const steady = []
async function runClient(c, idx) { const pending = new Map() c.onPatch((nonces) => { for (const n of nonces) { const p = pending.get(n) if (p) { pending.delete(n) p(performance.now()) } } }) for (let r = 0; r < ROUNDS; r++) { const nonce = idx * 100000 + r + 1 const t0 = performance.now() const arrival = new Promise((res) => pending.set(nonce, res)) const timeout = new Promise((res) => setTimeout(() => res(null), 30000)) await c.dispatch({ id: idx % 200, nonce }) const t1 = await Promise.race([arrival, timeout]) if (t1 === null) continue const dt = t1 - t0 if (r === 0) first.push(dt) else steady.push(dt) if (THINK_MS) await sleep(THINK_MS) } }
proxy.reset() const connsBefore = proxy.stats.connections const t0 = performance.now() await Promise.all(clients.map(runClient)) const wallMs = performance.now() - t0
results.push({ rtt, variant: v.name, connect: summarize(connectSamples), first: summarize(first), steady: summarize(steady), // New TCP connections opened DURING the command phase. This is the // handshake claim, measured rather than asserted. newConns: proxy.stats.connections - connsBefore, opsPerSec: Math.round((first.length + steady.length) / (wallMs / 1000)), })
for (const c of clients) c.close() await sleep(200) await proxy.close() await server.stop() await sleep(400) console.error(` done rtt=${rtt} ${v.name}`) }}
console.log(`\n=== Test 2: command -> patch round trip (${CLIENTS} clients x ${ROUNDS} rounds) ===\n`)console.log( table(results, [ { label: 'rtt', get: (r) => `${r.rtt}ms` }, { label: 'variant', get: (r) => r.variant }, { label: 'connect p50', get: (r) => `${r.connect.p50}` }, { label: '1st cmd p50', get: (r) => `${r.first.p50}` }, { label: 'steady p50', get: (r) => `${r.steady.p50}` }, { label: 'steady p95', get: (r) => `${r.steady.p95}` }, { label: 'steady p99', get: (r) => `${r.steady.p99}` }, { label: 'new TCP conns', get: (r) => r.newConns }, { label: 'ops/s', get: (r) => r.opsPerSec }, ]),)
console.log('\n' + JSON.stringify({ test: 'rtt', clients: CLIENTS, rounds: ROUNDS, results }))