使用 <link rel="preload"> 加载资源时,Chrome 中加载顺序行为不一致。

3
我正在尝试根据用户连接的navigator.connection.effectiveType动态添加<link rel="preload">标签来加载字体文件。例如,如果有效类型为“4g”,则在任何其他资源之前将<link as="font" type="font/woff2" rel="preload" crossorigin="anonymous" href="inter-var.woff2">注入到head标记中,如果连接是“slow-2g”/“2g”/“3g”,则不注入link
我还使用preload加载其他资源,但它们不像字体那样关键,因此它们会在字体文件之后注入。
<head>
  // some other code
  <script id="connection-type-checker">
    (() => {
      const inter = document.createElement('link')
      const interItalic = document.createElement('link')
      const firaCode = document.createElement('link')

      inter.as = 'font'
      inter.type = 'font/woff2'
      inter.rel = 'preload'
      inter.crossOrigin = 'anonymous'
      inter.href = 'inter-var.woff2'

      interItalic.as = 'font'
      interItalic.type = 'font/woff2'
      interItalic.rel = 'preload'
      interItalic.crossOrigin = 'anonymous'
      interItalic.href = 'inter-var-italic.woff2'

      firaCode.as = 'font'
      firaCode.type = 'font/woff2'
      firaCode.rel = 'preload'
      firaCode.crossOrigin = 'anonymous'
      firaCode.href = 'fira-code.woff2'

      const insertAfter = (newNode, referenceNode) => referenceNode
        .parentNode.insertBefore(newNode, referenceNode.nextSibling)

      const target = document.getElementById('connection-type-checker')

      insertAfter(inter, target)
      insertAfter(interItalic, target)
      insertAfter(firaCode, target)
    })()
  </script>

  // **This is where <link>s get injected**

  // some other code...

  <link as="script" rel="preload" href="script.js" crossorigin="anonymous">
</head>

The problem I'm facing is that Chrome doesn't keep the original order for resources loaded with link preload if the link element was created with JavaScript (if link elements are inlined as HTML in the head tag everything works as expected).

Screenshot:

  • Safari(遵守原始顺序)
  • Chrome(不遵守原始顺序)
  • Firefox(不支持链接预加载)

Safari, Chrome, Firefox

我正在尝试理解为什么原始顺序在Chrome中被打乱了,以及是否可以修复?

1个回答

1

我是一名Chrome工程师。据我所知,这里存在一些不一致之处:

  1. 首先,从你提供的图片来看,Firefox实际上在预加载之前就已经获取了image.jpeg
  2. 其次,我偶尔也会让Safari产生奇怪的排序:

Safari ordering

您所看到的是 Chrome (以及一些其他浏览器)后台 HTML 解析器的工作,这只是另一个轻量级解析器,可以快速扫描页面寻找需要提前获取的资源。通过在您创建的示例页面上调试 Chrome,事件发生的顺序大致如下:
  1. 预读解析器启动对 script.js 的请求
  2. 预读解析器启动对 image.jpeg 的请求
  3. 常规解析器执行文档挂起的阻止解析脚本
  4. 三个预读取操作按添加顺序进行获取
因此,在这种情况下,您可以看到预读/后台解析器稍微领先了一步,通过您的 script 标签开始获取资源,而主解析器则无法及时响应。大多数浏览器都有这种类型的解析器 这里是一篇相关文章,不幸的是它没有任何标准规定,因为它不应该有任何可观察到(针对应用程序代码)的影响。
然而,如果您因此看到性能问题,最好的选择是在https://crbug.com上提交一个Chromium bug,并且也让我知道,我可以将其放在正确的人面前。
顺便说一下,我注意到您已经提交了https://github.com/w3c/preload/issues/146,如果可以的话,我可能会关闭它,支持您提交Chrome bug。

错误已经在 https://bugs.chromium.org/p/chromium/issues/detail?id=1074587 报告。 - iamskok
1
谢谢,我已经把一个人抄送到了这个错误报告中。 - Dominic Farolino
非常感谢!你能想到任何方法欺骗后台HTML解析器并按照确切的顺序加载资源吗? - iamskok
1
老实说,在不彻底改变文档布局的情况下,我认为你没有太多可以做的。 Chrome 有一些计划,使 Background HTML 解析器向主线程让步,但我不确定这与此问题有多少交集: https://groups.google.com/a/chromium.org/forum/?oldui=1#!topic/loading-dev/rhHhUoZ4LD4 - Dominic Farolino

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接