There never was a good knife made of bad steel. — Benjamin Franklin
- Preload critical assets to improve loading speed
- Don’t fight the browser preload scanner
- 渲染页面:浏览器的工作原理 - Web 性能 | MDN
- How the Browser Pre-loader Makes Pages Load Faster
浏览器自身也会做很多优化手段来提高性能,预加载扫描器就是其中之一。
什么是预加载扫描器?
每个浏览器都有个主要的HTML解析器,用于将标记原始标记并将其转化为对象模型。但是当解析器遇到阻塞资源时会暂停,例如加载了<link>
元素的样式表,或者加载了没有async
或defer
属性的<script>
会暂停原因如下:
<link>
元素的样式表:防止出现无样式内容(FOUC:flash of unstyled cntent),即在应用样式之前短暂看到无样式页面- 没有
async
或defer
属性的<script>
:当HTML解析器还没完成时,无法确定任何给定的脚本会修改DOM(一般做法是把script放到文档末尾)
阻塞任何一个关键渲染路径都是不可取的,这会延迟其他重要资源的发现而阻碍进程。浏览器通过称为预加载扫描器的辅助HTML解析器来尽力缓解这些问题。
该图描述了预加载扫描器如何与主 HTML 解析器并行工作以推测性地加载资源。在这里,主 HTML 解析器在开始处理
<body>
元素中的图像标记之前加载和处理 CSS 时被阻止,但预加载扫描器可以在原始标记中继续向前查找,以找到该图像资源并开始在主 HTML 解析器解除阻塞之前加载它。
可能破坏预加载扫描器的行为
动态注入脚本
不要在脚本中使用DOM注入脚本,如下所示:
<script>
// 默认注入的脚本是async
const scriptEl = document.createElement('script');
scriptEl.src = '/yall.min.js';
document.head.appendChild(scriptEl);
</script>
根据需要使用<script>
以及defer
和async
属性
首屏JavaScript懒加载
不要在首屏使用基于JavaScript的懒加载:
<img data-src="/sand-wasp.jpg" alt="Sand Wasp" width="384" height="255">
使用data-
前缀是使用JavaScript实现懒加载的常见形式。
例如上方代码所示,通过JavaScript检查视口并在可见时将data-src
替换为src
属性
由于预加载扫描器读取src、srcset等属性,设置为data-src会导致图像引用无法被发现。
CSS背景图像
预加载扫描器也无法扫描到CSS背景图像。
与HTML一样,浏览器将CSS处理为自己的对象模型,称为CSSOM。如果在构建CSSOM过程中发现外部资源,则在发现时请求这些资源,而不是由预加载扫描器请求。
此情况可使用rel-preload
提前获取该图像:
<!-- Make sure this is in the <head> below any
stylesheets, so as not to block them from loading -->
<link rel="preload" as="image" href="lcp-image.jpg">
过多的内联资源
内联资源可能比下载资源更快,因为不会发起单独的请求。它就在文档中,并且会立即加载。然而它也有明显缺点:
- 内联资源无法被单独缓存
- 无法在多个文档中共享
- 内联太多,会延迟预加载扫描器发现后面的资源(先下载内联资源,如CSS中的字体)