提高渲染速度,怎么让资源预加载?

646 阅读4分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

为什么需要预加载?

浏览器同时发出并发请求数是有限制的,受最大tcp连接数限制,单个tcp连接,在同一时间只能处理一个http请求(只的是http/1.1,http2支持多路复用),请求一般像Chrome为6个,因此资源获取的时机以及优先级便尤为重要。

Link 标签 rel="preload"

该属性可以指明哪些资源是在页面加载完成后即刻需要的。对于这种即刻需要的资源,你可能希望在页面加载的生命周期的早期阶段就开始获取,在浏览器的主渲染机制介入前就进行预加载。这一机制使得资源可以更早的得到加载并可用,且更不易阻塞页面的初步渲染,进而提升性能。

<link href="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.js" rel='preload' as='script'/>

通过 HTTP header 方式:

Link: <https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.js>; rel=preload; as=script

除了rel之外还需要通过hrefas属性指定需要被预加载资源的资源路径及其类型

as属性的作用

as属性是必须要设置的,使用as来指定将要预加载的内容的类型,将使得浏览器能够:

  • 更精确地优化资源加载优先级。
  • 匹配未来的加载需求,在适当的情况下,重复利用同一资源。
  • 为资源应用正确的内容安全策略。
  • 为资源设置正确的 Accept 请求头。
    如果未设置或者设置错误as属性,则将不能提高其加载优先级

哪些资源可以被预加载?

  • audio: 音频文件。
  • document: 一个将要被嵌入到<frame><iframe>内部的HTML文档。
  • embed: 一个将要被嵌入到<embed>元素内部的资源。
  • fetch: 那些将要通过fetchXHR请求来获取的资源,比如一个ArrayBufferJSON文件。
  • font: 字体文件。
  • image: 图片文件。
  • object: 一个将会被嵌入到元素内的文件。
  • script: JavaScript文件。
  • style: 样式表。
  • track: WebVTT文件。
  • worker: 一个JavaScript的web workershared worker
  • video: 视频文件。

Link 标签 rel="prefetch"

**页面资源预加载(Link prefetch)**是浏览器提供的一个技巧,目的是:让浏览器在空闲时间下载或预读取一些文档资源,用户在将来将会访问这些资源。一个 Web 页面可以对浏览器设置一系列的预加载指示,当浏览器加载完当前页面后,它会在后台静悄悄的加载指定的文档,并把它们存储在缓存里。当用户访问到这些预加载的文档后,浏览器能快速的从缓存里提取给用户。优先级会低于preload

<link rel="prefetch" href="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.js">

资源正在被加载时点击了某个链接

当用户点击一个连接,或开始任何形式的页面加载时,预取操作将被停止且任何预取提示将被丢弃。如果一个预取文档只下载了一部分,那么这部分文档将被保存在缓存中,供服务端发送一个 "Accept-Ranges: bytes" 的返回头。这个返回头通常是由网络服务器在返回静态内容时生成的。当用户真正访问这个已经(部分)预载过的文档时,该文档的剩余部分将被通过一个 HTTP byte-range 的请求获取。

Link 标签 rel="prerender"

这是一个重量级的选项,它可以让浏览器提前加载指定页面的所有资源。

<link rel="prerender" href="/nextpage.html"/>

要小心的使用 prerender,因为它将会加载很多资源并且可能造成带宽的浪费,尤其是在移动设备上。还要注意的是

Link 标签 rel="subresource"

被Chrome支持了有一段时间,已经移除不必关注,并且已经有些搔到预加载当前导航/页面(所含有的资源)的痒处了。但它有一个问题——没有办法处理所获取内容的优先级(as也并不存在),所以最终,这些资源会以一个相当低的优先级被加载,这使得它能提供的帮助相当有限。


webpack中的使用

利用import()动态加载脚本并设置魔法注释实现

const NotFound = asyncLoad(() => import(/*webpackPrefetch: true */'pages/not-found'));

const NotFound = asyncLoad(() => import(/*webpackPreload: true */'pages/not-found'));

利用preload-webpack-plugin

preload-webpack-plugin 传送门

参考链接