用css或javascript实现预加载_用 preload 预加载页面资源

本文深入探讨了preload预加载技术的使用,包括如何通过link标签和HTTP响应头创建预加载,浏览器支持情况,以及与prefetch的区别。文章强调了正确设置preload以提升资源加载优先级的重要性,并提醒开发者避免滥用、混用和错用preload,以防止增加页面负担。同时,介绍了不同资源的加载优先级规则,帮助优化前端性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

(给前端大学加星标,提升前端技能.)

作者:felix

https://github.com/ProtoTeam/blog/blob/master/201802/1.md

本文主要介绍preload的使用,以及与prefetch的区别。然后会聊聊浏览器的加载优先级。

preload 提供了一种声明式的命令,让浏览器提前加载指定资源(加载后并不执行),在需要执行的时候再执行。提供的好处主要是

  • 将加载和执行分离开,可不阻塞渲染和 document 的 onload 事件

  • 提前加载指定资源,不再出现依赖的font字体隔了一段时间才刷出

如何使用 preload

使用 link 标签创建

rel="preload" href="/path/to/style.css" as="style">

const link = document.createElement('link');

link.rel = 'preload';

link.as = 'style';

link.href = '/path/to/style.css';

document.head.appendChild(link);

使用 HTTP 响应头的 Link 字段创建

Link: <https://example.com/other/styles.css>; rel=preload; as=style

如我们常用到的 antd 会依赖一个 CDN 上的 font.js 字体文件,我们可以设置为提前加载,以及有一些模块虽然是按需异步加载,但在某些场景下知道其必定会加载的,则可以设置 preload 进行预加载,如:

rel="preload" as="font" href="https://at.alicdn.com/t/font_zck90zmlh7hf47vi.woff">

rel="preload" as="script" href="https://a.xxx.com/xxx/PcCommon.js">

rel="preload" as="script" href="https://a.xxx.com/xxx/TabsPc.js">

如何判断浏览器是否支持 preload

目前我们支持的浏览器主要为高版本 Chrome,所以可放心使用 preload 技术。其他环境在 caniuse.com 上查到的支持情况如下:

3daed2cf553b4752e9e52f5ead2d2218.png

在不支持 preload 的浏览器环境中,会忽略对应的 link 标签,而若需要做特征检测的话,则:

const isPreloadSupported = () => {

const link = document.createElement('link');

const relList = link.relList;

if (!relList || !relList.supports) {

return false;

 }

return relList.supports('preload');

};

如何区分 preload 和 prefetch

  • preload   是告诉浏览器页面必定需要的资源,浏览器一定会加载这些资源;

  • prefetch 是告诉浏览器页面可能需要的资源,浏览器不一定会加载这些资源。

preload 是确认会加载指定资源,如在我们的场景中,x-report.js 初始化后一定会加载 PcCommon.js 和 TabsPc.js, 则可以预先 preload 这些资源;

prefetch 是预测会加载指定资源,如在我们的场景中,我们在页面加载后会初始化首屏组件,当用户滚动页面时,会拉取第二屏的组件,若能预测用户行为,则可以 prefetch 下一屏的组件。

preload 将提升资源加载的优先级

使用 preload 前,在遇到资源依赖时进行加载:8813219574be257f9fa3337de91367e9.png使用 preload 后,不管资源是否使用都将提前加载:608f84e6c00a0e150fa5183ea14abd96.png可以看到,preload 的资源加载顺序将被提前:f85c12b6c277f267954cfeb23288f25d.png

避免滥用 preload

使用 preload 后,Chrome 会有一个警告:5da7cc0333f38c04741b654458826c74.png

如上文所言,若不确定资源是必定会加载的,则不要错误使用 preload,以免本末倒置,给页面带来更沉重的负担。

当然,可以在 PC 中使用 preload 来刷新资源的缓存,但在移动端则需要特别慎重,因为可能会浪费用户的带宽。

避免混用 preload 和 prefetch

preload 和 prefetch 混用的话,并不会复用资源,而是会重复加载。

rel="preload" href="https://at.alicdn.com/t/font_zck90zmlh7hf47vi.woff" as="font">

rel="prefetch" href="https://at.alicdn.com/t/font_zck90zmlh7hf47vi.woff" as="font">

使用 preload 和 prefetch 的逻辑可能不是写到一起,但一旦发生对用一资源 preload 或 prefetch 的话,会带来双倍的网络请求,这点通过 Chrome 控制台的网络面板就能甄别:c7e4ffdddaa31904856cac4bcb39f10b.png

避免错用 preload 加载跨域资源

若 css 中有应用于已渲染到 DOM 树的元素的选择器,且设置了 @font-face 规则时,会触发字体文件的加载。而字体文件加载中时,DOM 中的这些元素,是处于不可见的状态。对已知必加载的 font 文件进行预加载,除了有性能提升外,更有体验优化的效果。

在我们的场景中,已知 antd.css 会依赖 font 文件,所以我们可以对这个字体文件进行 preload:

rel="preload" as="font" href="https://at.alicdn.com/t/font_zck90zmlh7hf47vi.woff">

然而我发现这个文件加载了两次:e4b33c197f2560b46429d09929717144.pnga4708544cf7725436936538163a9af59.pngb19d35051a3d1c40390ac9354885c972.png

原因是对跨域的文件进行 preload 的时候,我们必须加上 crossorigin 属性:

rel="preload" as="font" crossorigin href="https://at.alicdn.com/t/font_zck90zmlh7hf47vi.woff">

再看一下网络请求,就变成一条了。

W3 规范是这么解释的:

Preload links for CORS enabled resources, such as fonts or images with a crossorigin attribute, must also include a crossorigin attribute, in order for the resource to be properly used.

那为何会有两条请求,且优先级不一致,又没有命中缓存呢?这就得引出下一个话题来解释了。

不同资源加载的优先级规则

我们先来看一张图:b5d83f1de908484b0a38a1a5b3ee2e95.png

这张表详见:Chrome Resource Priorities and Scheduling

这张图表示的是,在 Chrome 46 以后的版本中,不同的资源在浏览器渲染的不同阶段进行加载的优先级。在这里,我们只需要关注 DevTools Priority 体现的优先级,一共分成五个级别:

  • Highest 最高

  • Hight 高

  • Medium 中等

  • Low 低

  • Lowest 最低

be68fbaf7f1fb8f784a80dda2a2cb35b.png

html 主要资源,其优先级是最高的

92a80fb6f2674ac348c4eea95c7e18b5.png75bfbf8bef8647f939f09c01a9491bc5.png

css 样式资源,其优先级也是最高的

bb606426ec1d9bcc7300d58dd173a315.pngCSS(match) 指的是对已有的 DOM 具备规则的有效的样式文件。a88245d9b6b894bdeeb139fff8f0cf49.png

script 脚本资源,优先级不一

438fde09aa7dcd59b2760f27019f0dec.pngfb639a43941029519c9ec219053e59b4.png前三个 js 文件是写死在 html 中的静态资源依赖,后三个 js 文件是根据首屏按需异步加载的组件资源依赖,这正验证了这个规则。

font 字体资源,优先级不一

7e2f4e97a6b1f4c15e5addf336400267.png176b6901dddc03675265302440077aec.pngcss 样式文件中有一个 @font-face 依赖一个 font 文件,样式文件中依赖的字体文件加载的优先级是 Highest;在使用 preload 预加载这个 font 文件时,若不指定 crossorigin 属性(即使同源),则会采用匿名模式的 CORS 去加载,优先级是 High,看下图对比:第一条 High 优先级也就是 preload 的请求:619ee83e9c1dbe712aefe2348d4b6b0d.png

第二条 Highest 也就是样式引入的请求:7a2613c4018134759b11cdb9817ca6ce.png

可以看到,在 preload 的请求中,缺少了一个 origin 的请求头字段,表示这个请求是匿名的请求。让这两个请求能共用缓存的话,目前的解法是给 preload 加上 crossorigin 属性,这样请求头会带上 origin, 且与样式引入的请求同源,从而做到命中缓存:

rel="preload" as="font" crossorigin href="https://at.alicdn.com/t/font_zck90zmlh7hf47vi.woff">

这么请求就只剩一个:a8a121e2788c1f420f31e01e38c7058a.pngd29106f5bfc30cd960e8612416f64cfd.png在网络瀑布流图中,也显示成功预加载且后续命中缓存不再二次加载:2a05925ee25b3f0ebdac219ac6fb751a.png

总结

preload 是个好东西,能告诉浏览器提前加载当前页面必须的资源,将加载与解析执行分离开,做得好可以对首次渲染带来不小的提升,但要避免滥用,区分其与 prefetch 的关系,且需要知道 preload 不同资源时的网络优先级差异。

preload 加载页面必需的资源如 CDN 上的字体文件,与 prefetch 预测加载下一屏数据,兴许是个不错的组合。

参考资料:

  • https://www.w3.org/TR/preload/

  • https://www.w3.org/TR/resource-hints/

  • Prioritizing Your Resources with link rel='preload'

  • Preload, Prefetch And Priorities in Chrome

  • A Link: rel=preload Analysis From the Chrome Data Saver Team

88f60cb90915031cf59fa5065949efc5.png

分享前端好文,点个 在看 85eb409091158c446e0d5086bc0baf2c.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值