Skip to content

Track fetch() and stop waiting for requests after 15 s - #574

Merged
CodeByZach merged 2 commits into
candidate-2.0from
fetch
Nov 10, 2026
Merged

CodeByZach merged 2 commits into
candidate-2.0from
fetch

Conversation

@CodeByZach

Copy link
Copy Markdown
Owner

Tracks fetch() requests and stops pace from waiting forever for a request that never ends.

  • fetch() is tracked by default, with the same rules as XMLHttpRequest (trackMethods, restartOnRequestAfter, ignoreURLs, Pace.ignore, Pace.track). A fetch ends when its promise settles, on the response's headers, so a streaming body doesn't hold the bar. Pace's wrapper passes this and the arguments through unchanged, never touches a Request's body, and returns a promise that behaves like the native one. ajax: { trackFetch: false } turns it off.
  • ajax.maxWait (15000 ms by default): pace waits for each request at most that long after it was sent, then stops waiting for it. The request itself keeps going. Before, a request that never ended held the bar near 100% forever, and a WebSocket that never connected held it until the browser gave up (minutes in Chrome, never in Safari). false turns the limit off.
  • ajax.ignoreURLs patterns see the URL as the page wrote it, the full URL, and for same-origin requests the part after the origin (/api/items?page=2), so a pattern matches however the request's URL was written.

The README documents all three, plus a note that long polling and slow background requests such as prefetching need ignoreURLs.

Tests: new fetch.spec.mjs and max-wait.spec.mjs, the ajax rule tests run for both XMLHttpRequest and fetch, and the request tests share one real local server (for responses in parts, requests that never end, and WebSocket handshakes). Each new behavior has a test that fails against the previous pace.js in Chromium, Firefox and WebKit; the others check that fetch keeps behaving like the native one.

- fetch() is tracked like XMLHttpRequest: the same trackMethods (GET by
  default), restartOnRequestAfter, ignoreURLs, Pace.ignore and Pace.track.
  Pace replaces window.fetch with a function that calls the original with
  the same this and arguments, never reads or copies a Request's body, and
  returns a promise that settles like the original's, so unhandled
  rejections are still reported. A fetch ends when that promise settles (on
  the response's headers, an error or an abort), since its body's progress
  can't be seen without reading it. ajax.trackFetch: false turns it off.
- ajax.maxWait (15000 ms by default): pace waits for each tracked request,
  WebSocket and request forced with Pace.track at most that long from when
  it was sent, then stops waiting for it for good. The request keeps going.
  Before, one request that never ended held the bar near 100% forever.
  false, or anything other than a number from 0 to 2^31 - 1 ms (the most a
  timer can wait; setTimeout treats Infinity, null and larger numbers as
  0), means no limit.
- ajax.ignoreURLs patterns see the URL as the page wrote it, the full URL,
  and for requests to the page's own origin the part after the origin
  (/api/items?page=2), so a pattern matches however the URL was written:
  relative or absolute, a string, a URL or a Request. An XMLHttpRequest's
  URL is read when open() uses it.

The real server the request tests use moves into the test fixtures, with
endpoints for responses that arrive in parts, requests that never end and
WebSocket handshakes that are never answered. The ajax rule tests now run
for both XMLHttpRequest and fetch.
The two tests that run the page's fake clock for 15 and 60 seconds ran
every timer and animation frame on the way, which took about 4 and 17
seconds of real time. They now run the clock only around the moments that
matter and jump over the rest with fastForward(), so each takes about half
a second and still fails if maxWait isn't applied or false doesn't turn
it off.
@CodeByZach
CodeByZach merged commit 7c41970 into candidate-2.0 Nov 10, 2026
5 checks passed
@CodeByZach
CodeByZach deleted the fetch branch November 10, 2026 14:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant