Execution Guide
Tool versions
| Tool | Version used | Notes |
|---|---|---|
| Node.js | 23.11.0 | any ≥ 18 with global fetch/ESM works |
| playwright-core | 1.62.1 | ships no browsers; see below |
| Chrome for Testing | 149.0.7827.55 (arm64) | reused from an existing Playwright cache |
| Python | 3.13 | only for python3 -m http.server in the manual labs |
playwright-core deliberately ships no browser binaries. src/lib/browser.mjs resolves one in
this order:
$CHROMEenvironment variable, if set- newest
chromium-NNNNin~/Library/Caches/ms-playwright(or~/.cache/ms-playwright) - a system Chrome/Chromium in the usual install locations
If none is found it fails with instructions rather than silently using a different engine.
Version sensitivity. Several findings here are version-dependent — scheduler.yield()
availability, LoAF support, and await tick cost have all changed within recent memory. Record
the version with any result you keep. docs/measured-results.md states the version used for
every number in this module.
Quick start
cd fe-01-execution-model-scheduling/src
npm install # playwright-core only, ~1 package
npm run ordering # experiments A, B, C (~40s)
npm run starvation # experiment D (~5s)
npm run layout # experiment E (~5s)
npm run frame-timing # experiment F (~10s)
npm run benchmark # the 7-strategy lab (~90s)
Or everything in sequence:
npm run all
Manual (browser) labs
Two labs are run by hand in a real browser, because the point is what you observe:
npm run serve # http://localhost:8080
| URL | Purpose |
|---|---|
/starvation.html | Step 2 — feel the difference between microtask and task chunking |
/lab.html | Step 4 — implement the strategies yourself (TODO stubs) |
web/bugs.js holds the failure lab (F1–F3) and is loaded from the console; see
steps/05-failure-lab.md.
Tuning the benchmark
All parameters are environment variables:
ROWS=50000 npm run benchmark # smaller dataset — find the worker crossover
THROTTLE=1 npm run benchmark # no CPU throttling (see warning below)
THROTTLE=20 npm run benchmark # low-end device simulation
REPS=5 npm run benchmark # more repetitions, tighter medians
QUERY=zulu npm run benchmark # different selectivity
TRIALS=100 npm run ordering # more ordering trials
WORK_MS=2000 npm run starvation # longer starvation window
COUNT=3000 npm run layout # more elements to thrash
Throttling is not optional for meaningful results. THROTTLE=1 on a modern laptop produces
numbers that describe your laptop, not your users. The default of 6× approximates a mid-tier
phone. Every table in this module was produced at 6×.
Reproducibility notes
- The dataset uses a seeded PRNG, so row contents are identical across runs and machines.
- Keystrokes are dispatched through CDP as trusted input events, not
dispatchEvent— which matters here specifically, because synthetic dispatch changes microtask interleaving (experiment B). - The benchmark reports medians of
REPSruns. Single runs vary by 30–50 % on the wall-clock columns; the ratios between strategies are the durable finding, not the absolute milliseconds. - Headless frame pacing is not real display pacing. Treat the
jankcolumn as directional.
Cleaning up
Nothing is installed globally and no state persists outside src/node_modules.
rm -rf src/node_modules