# A handler's clock is the listener's, not the event's

**Question.** In Playwright's synchronous Python API, if a script waits with
`time.sleep`, when do its event handlers run, and what time do they record?

**Why it came up.** On 2026-09-29 I drove the live Hesper page in headless
Chromium, concluded that its `load` event never fired, and told the page's team
so. It fires at under a second. My own script was the problem.

**Method.** Playwright 1.62.0, headless Chromium, Python 3.12, on the server,
against `https://example.com/` (a neutral page). `goto(wait_until="commit")`
returns before the page has loaded; then the script waits five seconds, either
with `time.sleep(5)` or with `page.wait_for_timeout(5000)`, and looks at what
its `load` and `requestfinished` handlers have recorded, stamped with
`time.time()` inside the handler.

- `sleep-vs-wait.py`, output `run-2026-09-29.txt`: two trials of each.
- `browser-clock.py`, output `run-browser-clock-2026-09-29.txt`: the handler's
  time for `load` against the browser's own record of it
  (`performance.timeOrigin + loadEventStart` from the navigation entry).

**Result.**

| wait | handlers had run when the wait ended | `load` as the handler stamped it | `load` as the browser recorded it |
|---|---|---|---|
| `time.sleep(5)` | none | 5.15–5.32 s | 0.46 s |
| `page.wait_for_timeout(5000)` | all | 0.29–0.37 s | 0.36 s |

Under `time.sleep` nothing is delivered during the sleep; the events queue, and
the next call into Playwright (here `page.title()`) runs every handler at once,
so each is stamped with the moment the script next asked, not the moment it
happened. With `wait_for_timeout` the handlers run as the events arrive and the
stamps agree with the browser's to within about 10 ms.

**What this is and is not.** Playwright documents the rule ("`time.sleep()`
leads to outdated state"; use `page.wait_for_timeout` instead,
https://playwright.dev/python/docs/library). What the docs do not show is the
second half: the late handlers do not only run late, they *record the wrong
time*, and a timing built from them looks like a slow or hung page. The browser
keeps the true times (`performance` entries, `request.timing`); read those.

Two trials each, one page, one machine. It is a demonstration of a mechanism,
not a benchmark.
