页面加载的优化

383 阅读3分钟

HTML的解析

在浏览器渲染引擎中,有一个HTML解析器,负责将HTML字节流转换为DOM结构。

网络进程中加载了多少数据,HTML解析器就会解析多少数据(不会等整个HTML文档加载完,再进行解析)

一般流程:

  1. 通过分词器,将字节流转换为token
  2. 将token解析为DOM节点
  3. 将DOM节点添加到DOM树中

解析HTML时遇到JS和CSS会怎么样

结论是:JS是全阻塞的,CSS是半阻塞的。

如果遇到script标签或者外部的JS文件,会阻塞DOM的解析和其他资源的加载,因为JS脚本可能会修改DOM结构。

如果遇到css文件,不会阻塞DOM的解析,但是会阻塞JS的加载,因为JS脚本中可能依赖最新样式。也会阻塞页面的渲染,在cssom树构建好之前,浏览器不会有任何显示,因为没有css的页面通常是凌乱的,无法使用的。

浏览器预加载

虽然在脚本执行的时候,构建DOM是不安全的。但我们仍然可以继续解析HTML,查看它所需要的资源。这就是现在很多浏览器支持的预解析。

当脚本正在执行时,仍然继续解析HTML,找到以来的文件,在后台并行的下载。当脚本执行完毕之后,这些文件可能已经下载完成,可以直接使用了。虽然脚本可能会改变HTML结构,导致一些“预测”的浪费,但是这不常见,预解析还是会带来性能上的提升。

prefetch

允许浏览器获取资源并存储在缓存中,他告诉浏览器未来可能会使用某个资源,浏览器会在空闲时间加载。

prefetch的分类:

  • DNS prefetch
  • Link prefetch
<link rel="prefetch" href="..." as="script">

prerender:和prefetch非常类似,优化了导航到下一页面的资源加载。区别是:prerender在后台渲染了整个页面。

<link rel="prerender" href="...">

preload

向浏览器声明一个需要提前加载的资源,当资源真正需要使用时,立即执行。

<link rel="preload" href="..." as="style">
或者
<script>
	const link = document.createElement('link');
  link.rel = "preload";
  link.href = '...';
  link.as = 'style';
  document.head.appendChild(link);
</script>

三者不同之处

  • 浏览器预解析和preload的区别

    浏览器的预解析,只能预先加载HTML声明的资源。但是preload指令事实上克服了这个限制,它允许预加载在CSS和JavaScript中定义的资源,并允许决定何时应用这个资源。

  • preload和prefetch的区别

    preload专注于当前页面,以更高的优先级加载资源。prefetch专注于下一个页面将要加载的资源,并以低优先级加载。

不同资源的优先级

一个资源有五个优先级:Highest High Medium Low Lowest

一般来说,HTML/CSS的优先级最高,其次是font字体资源,然后是图片资源(出现在视口>没有出现在视口)

  • 对于prefetch的资源,优先级默认为最低,Lowest
  • 对于preload的资源,可以通过as或者type指定优先级(比如通过as="style"指定,即使资源不是样式文件)
  • 没有as的会被当作异步请求

使用案例

  • 使用preload提前加载字体文件
  • 在onload中预加载第二屏的内容,这也用户滚动能更快看到次屏内容
  • 分析页面上的链接,使用prefetch加载下一跳页面的资源
  • 预测用户行为,比如在商品列表页,如果用户鼠标停留在某个商品超过一段时间,就去分析商品详情页所需要的资源进行preload

参考资料

使用 Preload/Prefetch 优化你的应用

什么是 Preload,Prefetch 和 Preconnect?