前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >使用 Preload&Prefetch 优化前端页面的资源加载「建议收藏」

使用 Preload&Prefetch 优化前端页面的资源加载「建议收藏」

作者头像
全栈程序员站长
发布于 2022-11-15 09:46:44
发布于 2022-11-15 09:46:44
1.5K00
代码可运行
举报
运行总次数:0
代码可运行

对于前端页面来说,静态资源的加载对页面性能起着至关重要的作用。本文将介绍浏览器提供的两个资源指令-preload/prefetch,它们能够辅助浏览器优化资源加载的顺序和时机,提升页面性能。

一、从一个实例开始

如上图所示,我们开发了一个简单的收银台,支付过程中可以展开优惠券列表选择相应的券。从动图可以看到,列表第一次展开时,优惠券背景有一个逐渐显示的过程,体验上不是很好。

问题的原因也很明显,由于背景使用了视觉特意设计的图片,优惠券列表展开时需要去加载图片,背景渐显的过程实际上就是图片加载的过程;当网速慢的时候,这个问题会更加明显。那么,怎样解决这个问题呢?

仔细分析一下,我们会发现问题的原因在于背景图的加载时机太晚。

如果能在优惠券列表渲染前加载好背景图,这个问题就不会出现。从这个思路出发,我们可能想到以下两个方案:

  1. 使用内联图片,也就是将图片转换为base64编码的data-url。这种方式,其实是将图片的信息集成到css文件中,避免了图片资源的单独加载。但图片内联会增加css文件的大小,增加首屏渲染的时间。
  2. 使用js代码对图片进行预加载
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
preloadImage() {
    const imgList = [
        require('@/assets/imgs/error.png'),
        require('@/assets/imgs/ticket_bg.png')
    ];
    for (let i = 0; i < imgList.length; i++) {
        const newIMG = new Image();
        newIMG.src = imgList[i];
    }
}

Jetbrains全家桶1年46,售后保障稳定

这种方案主要是利用浏览器的缓存机制,由js代码在特定时机提前加载相应图片,优惠券列表渲染时就可以直接从缓存获取。不过,这种方案增加了额外的代码,需要自己控制好加载时机,并且将图片的url硬编码在了逻辑中。

可以看出,以上两种方案能够解决我们的问题,但都存在一些缺点。

那么,有没有更好的解决方案呢?答案是prefetch-一种由浏览器原生提供的预加载方案。

二、什么是prefetch?

prefetch(链接预取)是一种浏览器机制,其利用浏览器空闲时间来下载或预取用户在不久的将来可能访问的文档。网页向浏览器提供一组预取提示,并在浏览器完成当前页面的加载后开始静默地拉取指定的文档并将其存储在缓存中。当用户访问其中一个预取文档时,便可以快速的从浏览器缓存中得到。–MDN

具体来说,浏览器通过<link rel=”prefetch” href=”/library.js”>标签来实现预加载。

其中rel=”prefetch”被称为Resource-Hints(资源提示),也就是辅助浏览器进行资源优化的指令。

类似的指令还有rel=”preload”,我们会在后文提及。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<head>
    ...
    <link rel="prefetch" href="static/img/ticket_bg.a5bb7c33.png">
    ...
</head>

查看现在优惠券列表的加载效果。

果然,成功达成了我们期望的效果。那么浏览器是如何做的呢?我们打开Chrome的Network面板一探究竟:

可以看到,在首屏的请求列表中已经出现了优惠券背景图ticket_bg.png的加载请求,请求本身看起来和普通请求没什么不同;展开优惠券列表后,network中增加了一次新的ticket_bg.png访问请求,我们很快发现,这个请求的status虽然也是200,但有一个特殊的标记—prefetch cache,表明这次请求的资源来自prefetch缓存。这个表现验证了上文中prefetch的定义,即浏览器在空闲时间预先加载资源,真正使用时直接从浏览器缓存中快速获取。

三、Preload

从上面的案例,我们体会到了浏览器预加载资源的强大能力。实际上,预加载是一个广义的概念,prefetch只是具体实现方式之一,本节我们介绍下另外一种预加载方式preload。上文我们提到,preload与prefetch同属于浏览器的Resource-Hints,用于辅助浏览器进行资源优化。为了对两者进行区分,prefetch通常翻译为预提取,preload则翻译为预加载。

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

简单来说,就是通过<link rel=”preload” href=”xxx” as=”xx”>标签显式声明一个高优先级资源,强制浏览器提前请求资源,同时不阻塞文档正常onload。我们同样用一个实际案例进行详细介绍。

上图是我们开发的另外一个收银台,出于本地化的考虑,设计上使用了自定义字体。开发完成后我们发现,页面首次加载时文字会出现短暂的字体样式闪动(FOUT,Flash of Unstyled Text),在网络情况较差时比较明显(如动图所示)。究其原因,是字体文件由css引入,在css解析后才会进行加载,加载完成之前浏览器只能使用降级字体。也就是说,字体文件加载的时机太迟,需要告诉浏览器提前进行加载,这恰恰是preload的用武之地。

我们在入口html文件head加入preload标签:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<head>
    ...
    <link rel="preload" as="font" href="<%= require('/assets/fonts/AvenirNextLTPro-Demi.otf') %>" crossorigin>
    <link rel="preload" as="font" href="<%= require('/assets/fonts/AvenirNextLTPro-Regular.otf') %>" crossorigin>
    ...
</head>

再次查看页面首次加载的效果:

字体样式闪动的现象没有了!我们对比下使用preload前后的network面板。

使用前:

使用后:

可以发现字体文件的加载时机明显提前了,在浏览器接收到html后很快就进行了加载。

注意:preload link必须设置as属性来声明资源的类型(font/image/style/script等),否则浏览器可能无法正确加载资源。

四、Preload 和 Prefetch 的具体实践

1、preload-webpack-plugin

前文中我们举的两个例子,都是在入口html手动添加相关代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<head>
    ...
    <link rel="prefetch" href="static/img/ticket_bg.a5bb7c33.png">
    ...
</head>
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<head>
    ...
    <link rel="preload" as="font" href="<%= require('/assets/fonts/AvenirNextLTPro-Demi.otf') %>" crossorigin>
    <link rel="preload" as="font" href="<%= require('/assets/fonts/AvenirNextLTPro-Regular.otf') %>" crossorigin>
    ...
</head>

这显然不够方便,而且将资源路径硬编码在了页面中(实际上,ticket_bg.a5bb7c33.png后缀中的hash是构建过程自动生成的,所以硬编码的方式很多场景下本身就行不通)。webpack插件preload-webpack-plugin可以帮助我们将该过程自动化,结合htmlWebpackPlugin在构建过程中插入link标签。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const PreloadWebpackPlugin = require('preload-webpack-plugin');
...
plugins: [
  new PreloadWebpackPlugin({
    rel: 'preload'as(entry) {  //资源类型
      if (/\.css$/.test(entry)) return 'style';
      if (/\.woff$/.test(entry)) return 'font';
      if (/\.png$/.test(entry)) return 'image';
      return 'script';
    },
    include: 'asyncChunks', // preload模块范围,还可取值'initial'|'allChunks'|'allAssets',
    fileBlacklist: [/\.svg/] // 资源黑名单
    fileWhitelist: [/\.script/] // 资源白名单
  })
]

PreloadWebpackPlugin配置总体上比较简单,需要注意的是include属性。该属性默认取值’asyncChunks’,表示仅预加载异步js模块;如果需要预加载图片、字体等资源,则需要将其设置为’allAssets’,表示处理所有类型的资源。

但一般情况下我们不希望把预加载范围扩得太大,所以需要通过fileBlacklist或fileWhitelist进行控制。

对于异步加载的模块,还可以通过webpack内置的/_ webpackPreload: true _/标记进行更细粒度的控制。

以下面的代码为例,webpack会生成<link rel=”preload” href=”chunk-xxx.js” as=”script”>标签添加到html页面头部。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import(/* webpackPreload: true */ 'AsyncModule');

备注:prefetch的配置与preload类似,但无需对as属性进行设置。

2、使用场景

从前文的介绍可知,preload的设计初衷是为了尽早加载首屏需要的关键资源,从而提升页面渲染性能。

目前浏览器基本上都具备预测解析能力,可以提前解析入口html中外链的资源,因此入口脚本文件、样式文件等不需要特意进行preload。

但是一些隐藏在CSS和JavaScript中的资源,如字体文件,本身是首屏关键资源,但当css文件解析之后才会被浏览器加载。这种场景适合使用preload进行声明,尽早进行资源加载,避免页面渲染延迟。

与preload不同,prefetch声明的是将来可能访问的资源,因此适合对异步加载的模块、可能跳转到的其他路由页面进行资源缓存;对于一些将来大概率会访问的资源,如上文案例中优惠券列表的背景图、常见的加载失败icon等,也较为适用。

3、最佳实践

基于上面对使用场景的分享,我们可以总结出一个比较通用的最佳实践:

  • 大部分场景下无需特意使用preload
  • 类似字体文件这种隐藏在脚本、样式中的首屏关键资源,建议使用preload
  • 异步加载的模块(典型的如单页系统中的非首页)建议使用prefetch
  • 大概率即将被访问到的资源可以使用prefetch提升性能和体验

4、vue-cli3的默认配置

  • preload

默认情况下,一个Vue CLI应用会为所有初始化渲染需要的文件自动生成preload提示。这些提示会被@vue/preload-webpack-plugin注入,并且可以通过chainWebpack的config.plugin(‘preload’)进行修改和删除。

  • prefetch

默认情况下,一个Vue CLI应用会为所有作为async chunk生成的JavaScript文件(通过动态import()按需code splitting的产物)自动生成prefetch提示。这些提示会被@vue/preload-webpack-plugin注入,并且可以通过chainWebpack的config.plugin(‘prefetch’)进行修改和删除。

五、总结和踩坑

1、preload和prefetch的本质都是预加载,即先加载、后执行,加载与执行解耦。

2、preload和prefetch不会阻塞页面的onload。

3、preload用来声明当前页面的关键资源,强制浏览器尽快加载;而prefetch用来声明将来可能用到的资源,在浏览器空闲时进行加载。

4、不要滥用preload和prefetch,需要在合适的场景中使用。

5、preload的字体资源必须设置crossorigin属性,否则会导致重复加载。

原因是如果不指定crossorigin属性(即使同源),浏览器会采用匿名模式的CORS去preload,导致两次请求无法共用缓存。

6、关于preload和prefetch资源的缓存,在Google开发者的一篇文章中是这样说明的:如果资源可以被缓存(比如说存在有效的cache-control和max-age),它被存储在HTTP缓存(也就是disk cache)中,可以被现在或将来的任务使用;如果资源不能被缓存在HTTP缓存中,作为代替,它被放在内存缓存中直到被使用。

然而我们在Chrome浏览器(版本号80)中进行测试,结果却并非如此。将服务器的缓存策略设置为no-store,观察下资源加载情况。

可以发现ticket_bg.png第二次加载并未从本地缓存获取,仍然是从服务器加载。因此,如果要使用prefetch,相应的资源必须做好合理的缓存控制。

7、没有合法https证书的站点无法使用prefetch,预提取的资源不会被缓存(实际使用过程中发现,原因未知)。

8、最后我们来看下preload和prefetch的浏览器兼容性。

可以看到,两者的兼容性目前都还不是太好。好在不支持preload和prefetch的浏览器会自动忽略它,因此可以将它们作为一种渐进增强功能,优化我们页面的资源加载,提升性能和用户体验。

作者: Sha Chaoheng

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/226756.html原文链接:https://javaforall.cn

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022年10月30日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
用 preload 预加载页面资源
本文主要介绍preload的使用,以及与prefetch的区别。然后会聊聊浏览器的加载优先级。
ConardLi
2019/09/23
1.9K0
用 preload 预加载页面资源
Web 性能优化:Preload,Prefetch的使用及在 Chrome 中的优先级
今天,我们将深入研究Chrome 的网络栈,以明确 web 加载原语(如<link rel= preload > & <link rel= prefetch >) 背后的工作原理,以便你能够更有效地使用它们。
前端小智@大迁世界
2019/04/18
2.2K0
Web 性能优化:Preload,Prefetch的使用及在 Chrome 中的优先级
什么是 Preload、Prefetch 和 Preconnect?
今天我们将研究一下能显著提升页面性能的方法 —— 资源提示与指令。你也许听说过 preload,prefetch 和 preconnect,可是我们想研究的更深一点,搞清他们之间的区别并且充分的利用它们。它们带来的好处包括允许前端开发人员来优化资源的加载,减少往返路径并且在浏览页面时可以更快的加载到资源。
前端黑板报
2019/12/11
5.9K0
性能优化必知preload 和 prefetch
今天我们来探索一下前端资源的一些指令以及它们如何来提高网站性能的。你应该听过 preload 和 prefetch,但这次我们想深挖它们之间的不同以及如何受益于它们。它们允许开发者优化资源的传递时间、缩短往返次数等。
前端黑板报
2021/03/24
1.4K0
性能优化必知preload 和 prefetch
Resource Hints 知多少
在上篇文章 探究网页资源究竟是如何阻塞浏览器加载的 中介绍到 JS 会阻塞 DOM 的加载,样式会阻塞页面的渲染,外链样式里的自定义字体还会对文字造成闪动给用户带来不好的体验,诸如此类问题还有挺多,那到底该如何解决它们呢?
用户4456933
2021/06/01
1.2K0
Resource Hints 知多少
进阶 | 用 preload 预加载页面资源
前端爱好者的聚集地 本文主要介绍preload的使用,以及与prefetch的区别。然后会聊聊浏览器的加载优先级。 preload 提供了一种声明式的命令,让浏览器提前加载指定资源(加载后并不执行),在需要执行的时候再执行。提供的好处主要是 1. 将加载和执行分离开,可不阻塞渲染和 document 的 onload 事件 2. 提前加载指定资源,不再出现依赖的font字体隔了一段时间才刷出 如何使用 preload 使用 link 标签创建 使用 HTTP 响应头的 Link 字段创建 如我们常用到
用户1097444
2022/06/29
1.3K0
进阶 | 用 preload 预加载页面资源
Preload与Prefetch的区别以及webpack项目中如何优化
<link rel="preload" href="/path/to/style.css" as="style">
周陆军
2021/06/26
5.4K0
前端优化 之 preload
Preload的原理是在浏览器解析HTML文档时,提前加载页面所需的关键资源,如样式表、脚本文件和字体等。
Chester Chen
2024/03/25
1410
前端优化 之 preload
快速优化 Web 性能的10 个手段
优化网站的性能需要花费大量的时间,并且如果要根据自己的需求进行优化则花费的时间可能更多。
疯狂的技术宅
2020/09/01
1.9K0
快速优化 Web 性能的10 个手段
前端性能优化系列 | 加载优化
在浏览器发起网络请求时,并非每个字节都具有相同的优先级,所以,浏览器通常会对所要加载的内容进行推测,将相对重要的信息先呈现给用户。比如浏览器一般会先加载CSS,再去加载JavaScript脚本和图像文件。当然,浏览器的判断并不一定都是准确的,下面就来看看如何影响浏览器对资源加载的优先级。
用户6256742
2024/08/01
1260
前端性能优化系列 | 加载优化
前端性能优化总结
最近花了一些时间在项目的性能优化上,背后做了很多工作,但是最后依然没有达到自己想要的结果,有些失望,但是还是记录下自己的执着。
前端迷
2020/07/02
1.2K0
仅需 5 分钟,快速优化 Web 性能的10 个手段
作者:Marc 译者:前端小智 来源:dev 本人已经过原作者制授权翻译。 在这篇文章中,主要介绍10种快速提高网站性能的方法,你只需5分钟内就可以将它应用到你的网站上,废话不多说,让我们进入正题吧
前端小智@大迁世界
2020/10/28
7680
仅需 5 分钟,快速优化 Web 性能的10 个手段
前端性能优化总结
生产环境中,不需要打印日志。通过对webpack进行配置,打包时自动去掉console.log
前端进击者
2021/07/27
6260
从龟速 11s 到闪电 1s,详解前端性能优化之首屏加载
全文共6511字/词,阅读大概需要13分钟,太长不看党请直接移步👉「开始优化」部分直接查看优化手段 背景 前段时间公司服务器网络波动,网站访问变慢,一些性能问题也随之暴露了出来。纷纷反馈在这样的弱网条件下,访问新项目时,加载了近1分钟都没加载出来,而访问其他页面顶多也就30-40s。 在网络恢复后,尝试访问了下页面,无缓存首次打开需要等待近11s的时间,最大的资源达到了3.7M... 在对项目做了一些优化处理后,再次无缓存打开可以发现网页几乎是秒开,平均耗时在1s以内 在这里总结记录一下,基本上都是一些
@超人
2021/12/17
3.3K0
从龟速 11s 到闪电 1s,详解前端性能优化之首屏加载
“非主流”的纯前端性能优化
性能优化一直是前端研究的主要课题之一,因为不仅直接影响用户体验,对于商业性公司,网页性能的优劣更关乎流量变现效率的高低。例如 DoubleClick by Google 发现:
2020labs小助手
2020/09/23
5510
前端 Web 性能清单
考虑添加 preconnect 或 dns-prefetch 资源提示以建立与重要第三方来源的早期连接。
海拥
2023/05/23
1.1K0
前端 Web 性能清单
构建Vite知识体系-项目性能优化
传统的 HTTP 1.1 存在队头阻塞的问题,同一个 TCP 管道中同一时刻只能处理一个 HTTP 请求,也就是说如果当前请求没有处理完,其它的请求都处于阻塞状态,另外浏览器对于同一域名下的并发请求数量都有限制,比如 Chrome 中只允许 6 个请求并发(这个数量不允许用户配置),也就是说请求数量超过 6 个时,多出来的请求只能排队、等待发送。因此,在 HTTP 1.1 协议中,队头阻塞和请求排队问题很容易成为网络层的性能瓶颈。
泯泷、
2024/03/17
2490
[网页提速]preload的使用方法
前言:作为一名网站开发者,你可能已经听说过预加载(preload)了。预加载可以帮助我们在网页加载时提前加载一些资源,以提高网站的性能和用户体验。在这篇博客中,我将介绍preload的用法,并分享一些最佳实践。
堡主
2023/03/14
6980
prelink
现如今网络越来越快,网页应用也变得越来越受人们欢迎,与此同时,人们对应用响应速度的期望值也越来越高。 怎样提升网站的响应速度,怎样让用户更快的看到想要的内容已经变得越发重要了。 对此,除了开发者们绞尽脑汁优化应用外,浏览器产商们也提供了各种各样方式来帮助开发者预加载资源。
epoos
2022/10/28
5770
你不可能知道的骨架屏玩法!
作者曾所在我司广告事业部,广告承载方式是以刮刮卡、大转盘等活动页进行展示,然后用户参与出广告券弹层。
秋风的笔记
2021/08/27
1.9K0
你不可能知道的骨架屏玩法!
相关推荐
用 preload 预加载页面资源
更多 >
领券
社区富文本编辑器全新改版!诚邀体验~
全新交互,全新视觉,新增快捷键、悬浮工具栏、高亮块等功能并同时优化现有功能,全面提升创作效率和体验
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验