v153 · webtransport · send streams

The scheduler, made visible

The spec's scheduling rule is one sentence: bytes queued on strictly ordered streams are sent ahead of bytes queued on strictly ordered streams with lower send order — FIFO within each stream, fairness across groups. This page runs the explainer's own use cases through that sentence so you can watch what the rule does to a congested connection.

This is a labelled local model: observing real drain order needs an HTTP/3 server to receive the bytes, which this showcase cannot reach — and this build's native support is probed for real just below. The model implements exactly the spec's rule, nothing more; it is the explanation, and the probe is the evidence.

First: could this build do it natively?

probing…

local model — the spec's rule, no network

Two send groups, one congested connection

Explainer §6–8 in one scene: a media group sending one stream per video frame (newer frames get higher sendOrder, so a late joiner never waits for stale frames) and a sync group pushing two state blobs. Queue work, then drain the connection one chunk at a time.

media group (frames)

  • empty

sync group (state)

  • empty

sent on the wire, in order

    Queue a few frames and blobs, then drain. Each drain step picks by the spec's rule: within each group the highest sendOrder wins; the two groups share the link fairly (round-robin here — the spec leaves cross-group division implementation-defined).

    code path — the real API this models

    const media = transport.createSendGroup();
    const sync  = transport.createSendGroup();
    
    async function sendFrame(bytes, frameNo) {
      // One stream per frame; newer frames outrank older ones, so a slow link
      // skips ahead instead of replaying the past (explainer §6).
      const s = await transport.createUnidirectionalStream({
        sendGroup: media,
        sendOrder: frameNo,
      });
      const w = s.getWriter();
      await w.write(bytes);
      await w.close();
    }
    
    async function sendState(bytes) {
      const s = await transport.createUnidirectionalStream({
        sendGroup: sync, sendOrder: 0,       // unranked within its group
      });
      const w = s.getWriter();
      await w.write(bytes);
      await w.close();
    }

    see also