demo · v142 · performance

Transition Performance Lab

Click any tile to trigger a real view transition. A live performance panel measures every transition with performance.measure() and a PerformanceObserver watches for paint entries. The stress-test fires five transitions in rapid succession — watch the concurrent-guard skip the queued ones.

Live performance panel

Last duration
Avg duration
activeViewTransition
null
Transitions run
0
Skipped (guard)
0
Paint entries
0

How it works

Each click calls document.startViewTransition(). Before calling it we check document.activeViewTransition — if it's non-null a transition is still in flight and we skip, logging the guard action. performance.mark() / performance.measure() wrap the transition so we capture real wall-clock duration. A PerformanceObserver watching paint entries counts how many paint events fire during the sequence.

Code

// Concurrent guard + performance measurement
async function safeTransition(updateFn, label) {
  if (document.activeViewTransition) {
    console.log(`${label}: skipped — transition in flight`);
    return;
  }

  performance.mark(`vt-start-${label}`);

  const vt = document.startViewTransition(updateFn);

  // poll activeViewTransition until it clears
  const poll = () => {
    if (document.activeViewTransition) requestAnimationFrame(poll);
  };
  requestAnimationFrame(poll);

  await vt.finished;
  performance.mark(`vt-end-${label}`);
  performance.measure(`vt-${label}`, `vt-start-${label}`, `vt-end-${label}`);

  const [entry] = performance.getEntriesByName(`vt-${label}`);
  console.log(`${label}: ${entry.duration.toFixed(1)} ms`);
}

See also