link preload importance=low gets prioritized over blocking script importance=high
Reported by
jakub.g....@gmail.com,
Oct 25
|
||||
Issue descriptionUserAgent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36 Steps to reproduce the problem: 1. Use Canary and enable chrome://flags/#enable-experimental-web-platform-features 2. Load the HTML in attachment (or https://jg-testpage.github.io/wpt/preload-vs-blocking-script.html) which constains 3 blocking scripts (with importance=high) and one link preload script (with importance=low) (made up example loading random JS libs) What is the expected behavior? The 3 blocking scripts are sent earlier and get responses earlier than the preloaded resource What went wrong? Preloaded resource is almost always fetched first and gets the response first Did this work before? N/A Does this work in other browsers? N/A Chrome version: 72.0.3591.0 Channel: canary OS Version: 10.0 Flash Version: When you open "performance" tab in devtools, rerun the scenario, hover the requests in "network", you will observe that importance=low/high is assigned to the requests (see screenshot), but still the preload requests are always done first. Regardless if `importance` is set, always giving priority to preload over blocking scripts seems a bit too aggressive to me. But when importance is set explicitly and not respected, it's even worse. IMO prioritizing preload over everything else will harm its adoption. The workaround seems to also preload all sync scripts, but this results in code duplication which is not good, and prone to regressions.
,
Oct 25
,
Oct 26
,
Oct 26
Actually a more relevant example would be a different one, where the code preloads a heavy lib (in original example I preload a small file): https://jg-testpage.github.io/wpt/preload-vs-blocking-script-2.html When I run it in webpagetest in Canary with command line flag `--enable-experimental-web-platform-features`, it actually shows that the preload request is issued latest and with h2 priority LOWEST, so priority hints work correctly in that case: https://www.webpagetest.org/result/181026_FP_0e088aa1ba398b43a7b2d258396e6a1d/3/details/#waterfall_view_step1 https://www.webpagetest.org/result/181026_5M_baf0e40b74b4ca889f37c6a4f378c09f/1/details/#waterfall_view_step1 However locally on Chrome I see it as a first request, and also devtools don't show actual http/2 frames being transferred, contrary as WPT. I think this might be actually devtools being misleading than a real code issue. -- I am still worried though by a case where priority hints are missing in markup or not taken into account - in that case the preload is sent first, with priority MEDIUM as all other requests, and it's sometimes blocking the sync <script>s. See those waterfalls (without Chrome flag, hence `importance` is not taken into account): https://www.webpagetest.org/result/181026_QT_6919301bc9bbb6d41ec138088b26f3be/
,
Oct 26
> I think this might be actually devtools being misleading than a real code issue. Hmm, I'm not sure. Locally, I captured a netlog on Chrome Canary twice, visiting https://jg-testpage.github.io/wpt/preload-vs-blocking-script-2.html. Once with exp web platform features (Priority Hints) enabled, and once without. Both logs indicate that QUIC_CHROMIUM_CLIENT_STREAM_SEND_REQUEST_HEADERS associated with three.min.js appear before any other JS requests. Visiting the same site on WPT and capturing netlogs, I analyzed the logs for [1] and [2] (netlogs are attached), and the event stream indicates that Chromium requests three.js at least a millisecond before all other JS files as well. The behavior is the same as local. (Why WPT has a different ordering for the different runs I'm not sure, perhaps it is ordered by completion time or priority; nevertheless, the netlogs indicate that three.js is being requested first). With this, it seems that Chromium does the following in order (I've verified this by debugging locally as well): 1. Preload scanner speculatively preloads link rel=preload (three.js in this case) (DocumentLoader::StartPreload *-> ResourceFetcher::RequestResource) 2. Preload scanner then speculatively preloads the rest of the scripts in order of appearance (even though they appear before the link rel=preload in the document) (DocumentLoader::StartPreload *-> ResourceFetcher::RequestResource) 3. Main parser finally calls ResourceFetcher::RequestResource for each resource in order of appearance in document (the "expected" order). So I think the main question to ask is why does the preload scanner kick off a request for the later-appearing link rel=preload before the earlier-appearing scripts. +yoav as perhaps he may be able to lend some insight? Regarding the involvement of Priority Hints, if the requests were speculatively preloaded by the preload scanner in the "expected" order (or for example, the scanner were disabled), then the link rel=preload would indeed be fetched last with a low-priority, however it would only get queued behind the script requests on slow networks (this is subject to change if we can show more beneficial scenarios of Priority Hints, but for now this is the behavior). [1]: https://www.webpagetest.org/result/181026_53_da6810710fb2600b2e07483760ae59c9/ (WPT-vanilla run) [2]: https://www.webpagetest.org/result/181026_GZ_ef6058393bb968fe2e344615fb341197/ (WPT-enabled experimental web plat features run)
,
Oct 30
The answer is probably "AppCache support" :/ Link rel preloads can get triggered before the document element is created, because we assume old appcache content doesn't include them: https://cs.chromium.org/chromium/src/third_party/blink/renderer/core/html/parser/html_document_parser.cc?q=html_document_&sq=package:chromium&g=0&l=345 Other resources have to wait due to the possibility that AppCache may be registered for the page... So, this is WAI, given that we currently can't just rip out AppCache support, even if we really want to
,
Oct 30
Discussed this with domfarolino@ today and one way forward could be to prevent low-importance preloads from being requested before non-preload requests go out. This will unnecessarily stall those preloads, but will prevent them from "jumping the queue" before higher-importance non-preloaded resources.
,
Oct 31
Oh yeah, that was a fix we made for issue 629420 ... Not dispatching low-importance preloads before other requests can go out sounds sensible to me too.
,
Oct 31
> Chromium requests three.js at least a millisecond before all other JS files It seems that this problem of higher priority requests arriving couple of milliseconds after low priority requests goes beyond link-rel preload. I have seen other websites where developer happens to include low priority resources first, and Chrome happily goes and fetches them. This is immediately followed by requests for higher priority resources which may appear a bit later. e.g., https://www.webpagetest.org/result/181031_QF_007c4af86ba5eb017de693d6cc88045e/1/details/#waterfall_view_step1 has bunch of low priority requests followed by MEDIUM priority requests #32 and #33.
,
Oct 31
https://chromium-review.googlesource.com/c/chromium/src/+/720798 is my past attempt to tackle a similar problem at a slightly lower layer (which may or may not work for this case). |
||||
►
Sign in to add a comment |
||||
Comment 1 by jakub.g....@gmail.com
, Oct 25