Bug 252413 - WebKit is too conservative in its first paint threshold
Summary: WebKit is too conservative in its first paint threshold
Status: NEW
Alias: None
Product: WebKit
Classification: Unclassified
Component: Page Loading (show other bugs)
Version: WebKit Nightly Build
Hardware: Unspecified All
: P2 Normal
Assignee: Nobody
URL:
Keywords: InRadar
Depends on:
Blocks:
 
Reported: 2023-02-16 11:59 PST by Malte Ubl
Modified: 2023-07-18 02:22 PDT (History)
8 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Malte Ubl 2023-02-16 11:59:46 PST
- WebKit handles streaming HTTP responses very differently from other browsers.
- First we thought that it has a bigger minimum byte count to accept the initially flushed response but we have disproven that. - - You can add arbitrary bytes to the head, Webkit will still not paint early.
- Instead there seems to be a heuristic in place that requires a certain number of "contentful pixels" to be present to perform an initial paint.
- The way I established that is by making a demo which allows controlling the text amount in the initial streamed chunk via a query string.

Compare these two URLs and how they behave on Safari vs. Chrome (I tested on Desktop):
- https://streaming-threshold.vercel.app/api/stream?count=2000
- https://streaming-threshold.vercel.app/api/stream?count=1000

Note how they differ in the count of the "a" character. If you increase the font size of the "a" you need fewer to trigger the heuristic 🤯

I assume that the heuristic is in place to avoid certain "flashes of incomplete content". However, given that other browsers don't have this issue, it might make sense to align behavior with them. The primary consequence of the heuristic is that naive streaming demos don't work in Safari. This is likely not a problem for most real web pages that have more content, but we originally found this with a graphically sophisticated page that had little "content".
Comment 1 Alexey Proskuryakov 2023-02-20 10:26:37 PST
They way the trade-off is described in the report makes me think that what we do now is the right choice?
Comment 2 Simon Fraser (smfr) 2023-02-20 10:59:36 PST
This is about our first paint heuristic (we don't generally refer to this being about "streaming HTML").
Comment 3 Ben Nham 2023-02-20 12:25:33 PST
It would be better for someone on the rendering team to chime in on this. But the visually non empty heuristic (FrameView::checkAndDispatchDidReachVisuallyNonEmptyState) is indeed there to try and prevent flashes of white when navigating between pages, and also to save resources on paints that will be quickly replaced by other paints. The thresholds are already pretty low so I'm not sure that we should be decreasing them even more for real webpages.
Comment 4 Malte Ubl 2023-02-20 17:17:27 PST
This is likely a different threshold than the one to prevent white-paints between navigations (I'm a big fan of that one!)

Here we are talking about Safari not painting for 5 seconds+ while there is stuff to paint and other browsers paint.

Are you aware of a URL that behaves better with the heuristic?

Chrome's heuristic is:
- paint after 65KB
- paint before encountering a sync script tag in HTML body

The latter triggers paints at the right time for React's and Svelte's streaming implementations, because they always emit a script tag when they flush the buffer.
Comment 5 Radar WebKit Bug Importer 2023-02-23 12:00:19 PST
<rdar://problem/105845237>
Comment 6 Joseph Earl 2023-07-18 02:22:54 PDT
See https://github.com/vercel/next.js/issues/52444 for a reproducer