mirror of
https://github.com/vercel/next.js.git
synced 2026-09-20 02:25:18 +08:00
bdbbb1e887
This is a refactor of the prefetching algorithm to block the prefetch task from completing until the response is received. Currently, a prefetch task is fire-and-forget: once a prefetch's requests are spawned, the scheduler marks the originating task as complete regardless of what the server ends up returning. However, certain planned optimizations require us to verify the response from the server to determine whether additional work is necessary. For example, we may attempt to do a static prefetch instead of a runtime prefetch if we optimistically assume that the static prefetch does not vary on runtime data. We need to verify that assumption is correct before marking the task as complete. Now, whenever a pass over the task spawns a segment request, or encounters an entry whose response hasn't arrived yet, the task registers itself on the entry and exits as Blocked instead of Done. When the entry resolves, the blocked task is pinged and the pass re-runs against the received data. Only a pass that observes every response it cares about advances the task to the next phase or completes it. Rejected entries are handled per segment: a rejection counts as an observed response, so the pass skips that segment and keeps prefetching the rest. The task never registers on a rejected entry, since nothing ever pings one. Retries are governed by the existing per-entry logic. Also fixes a cache bug this exposed: when a revalidation response is keyed at a more generic vary path than the stale partial entry that prompted it (because the segment turned out not to vary on some param), the stale entry shadowed the result on every lookup — the upgraded data was unreachable and the revalidation was wasted. With blocking, that dead end became an infinite loop: each fulfillment re-pinged the blocked task, which re-read the same stale entry and spawned another revalidation. Upserting (or re-keying) a segment now deletes settled entries at more specific vary paths that the incoming entry supersedes. The router-act test helper's "at least one request initiated" watchdog is adjusted to account for the new blocking behavior: countable requests can now be legitimately gated on an in-flight App Shell response (which the watchdog intentionally doesn't count). On expiry it now proceeds to response processing if the act scope intercepted a shell request, and keeps waiting while shell requests are in flight elsewhere on the page, instead of timing out.