demo · v147

Trace upload

Worker A runs a real CPU-heavy load. A second worker profiles it with the JS Self-Profiling API at a chosen sample rate, aggregates the trace into a hot-functions list off the main thread, and emits a compact payload ready for navigator.sendBeacon.

Behind a flag: JS Self-Profiling in dedicated workers ships behind the Document Policy js-profiling, gated by chrome://flags/#enable-experimental-web-platform-features in Chrome 147. This page is served with the required policy header and reports unavailable browsers instead of fabricating traces.
samples collected
distinct functions
trace size (raw)
payload size (aggregated)
functionsamples
no profile yet

Aggregated payload (what we'd send to a telemetry endpoint)

no payload yet
pipeline idle

What's happening

  1. Worker A spins up a Worker that runs naïve fib(28), a heap-allocating JSON.parse, and an array sort.
  2. Worker A wraps the load in new self.Profiler({ sampleInterval }), calls .stop(), posts the raw trace.
  3. Main thread hands the raw trace to Worker B, which aggregates by leaf function — the "process traces in a worker" pattern from the WICG explainer.
  4. The compact payload is shown above. The button calls navigator.sendBeacon('/telemetry/profile', payload) for real.
// inside worker A (Chrome 147, Document-Policy: js-profiling)
const profiler = new self.Profiler({ sampleInterval: 10, maxBufferSize: 10000 });
doExpensiveWork();
const trace = await profiler.stop();
self.postMessage({ kind: 'trace', trace });

// main thread → worker B
workerB.postMessage({ kind: 'aggregate', trace });

see also

implementation reference

Need the exact API surface, compatibility boundaries, errors, lifecycle, and source links? Read the matching gendn reference ↗