fetchpriority资源优先级详解:浏览器加载排序与懒加载配合实战

fetchpriority资源优先级详解:浏览器加载排序与懒加载配合实战
张文保 14 分钟阅读 1,630 阅读
本文目录
  1. fetchpriority属性解决的是什么问题?
  2. 浏览器默认资源优先级怎么定?LCP主图为什么常被排到后面?
  3. fetchpriority的high、low、auto分别用在什么场景?
  4. 3C配件站的首屏大图如何用fetchpriority把LCP拉回绿区?
  5. loading=lazy和fetchpriority有什么区别?懒加载该用在哪些图上?
  6. decoding=async和fetchpriority是什么关系?
  7. 把所有资源都设成fetchpriority=high会有什么后果?
  8. 怎么验证fetchpriority真的生效了?用什么工具看?
  9. fetchpriority和preload资源提示如何分工?
  10. 常见问题解答
  11. fetchpriority=high加了却好像没效果,是什么原因?
  12. fetchpriority是排名因素吗?会直接影响SEO吗?
  13. 一个页面该给几张图设fetchpriority=high?
  14. fetchpriority和preload该用哪个,还是都用?
  15. 老浏览器不支持fetchpriority,会不会出问题?
  16. decoding=async该不该给首屏LCP图加?
  17. 权威参考资料
摘要:浏览器加载页面时会自己给每个资源估一个优先级,但这个估计常常和你的业务重点对不上,最典型的是首屏大图被排到一堆脚本后面下载。fetchpriority用来告诉浏览器哪张图该先下、哪张可以往后放。本文说明浏览器默认优先级怎么定,fetchpriority的high、low、auto各适用什么场景,loading=lazy和decoding=async怎么与它配合,并附一个3C配件站把LCP从3.4秒压到1.6秒的实操复盘。

站点慢,很多时候原因既不在资源体积,也不在服务器,在于该早下载的东西下晚了。同样的图、同样的带宽,加载顺序一变,首屏体验能差出一大截。这个顺序默认由浏览器自己决定,它的判断未必对。

我是保哥,做了二十多年SEO,这几年帮出海独立站做性能优化的项目越来越多。本文只讲fetchpriority这个属性:它不改资源的任何一个字节,只改浏览器下载的先后次序,却常常是把LCP从红区拉进绿区成本最低的一步。

fetchpriority属性解决的是什么问题?

可以把浏览器加载页面想象成一支人手有限的搬运队。HTML一边解析,一边发现需要的CSS、JS、图片和字体,全交给这支队伍去搬。同域并发连接数就那么几条,资源一多就得排队,谁先搬谁后搬要有个顺序。

浏览器排队有一套内部优先级:CSS和阻塞脚本几乎最高,可视区内的图片中等,屏幕外的图片很低。问题是,浏览器判断优先级依据的是资源类型和它当时能看到的信息,不是你的业务意图。它不知道哪张图是主打商品大图,也不知道哪个脚本可有可无。

fetchpriority补的就是这部分信息。它可以加在 img、link、script 这几个元素上,取值只有high、low、auto三个,作用是给浏览器一个提示,不是命令。按 web.dev关于Fetch Priority的说明,浏览器会尽量尊重你的偏好,但发生冲突时仍以它自己的判断为准。所以别把它当成能强制控制下载顺序的开关,原因后面细说。

浏览器默认资源优先级怎么定?LCP主图为什么常被排到后面?

绝大多数页面的LCP元素,也就是首屏最大的那块内容,往往是一张商品大图或banner。很多人以为浏览器会优先下载它,实际情况正好相反。

浏览器要判断一张图是否在首屏、尺寸够不够大,得先下完CSS、算出布局。在布局算出来之前,它给所有普通 img 同样偏低的优先级,先保证CSS和脚本。等它识别出这张图是LCP,已经过去几百毫秒,图还得重新排队。

这套默认次序有规范依据:HTML规范里关于抓取与优先级的章节写明了不同类型资源的默认优先级,以及fetchpriority如何介入调整,各家浏览器据此实现。因此fetchpriority不是某个厂商的私有特性,有规范背书,可以长期依赖。

用CSS背景图做主视觉的情况更糟:背景图要等对应元素的样式规则匹配上才开始下载,起步比 img 还晚。所以关键渲染路径与阻塞渲染的文章里反复强调,首屏主图尽量用 img 标签,不用CSS背景,这样浏览器才有机会提前提高它的优先级。用img标签引入,fetchpriority才有一个直接下手的地方。

fetchpriority的high、low、auto分别用在什么场景?

用法很简单。首屏LCP主图直接设为high:

<img src='hero.webp' fetchpriority='high' alt='主打充电宝'>

只需这一行。它告诉浏览器不必等布局算完,立即按高优先级下载这张图。link rel=preload 同样适用,预加载的字体或关键图配上fetchpriority=high,可以进一步排到队列前面。

low用在相反的方向:你知道不重要、又不打算改懒加载逻辑的资源。比如首屏下方的第三方小组件、非关键的装饰图、可以晚点执行的分析脚本,设为low就是主动让出带宽给关键资源。MDN对fetchpriority属性的定义写明,三个值里auto是默认值,表示不表态,由浏览器决定。

我的做法是:一个页面里high最好只给一到两个元素,通常就是那张LCP图,最多再加一个首屏关键字体。给多了等于没给,后面单独讲。low可以放开用,副作用小得多。

3C配件站的首屏大图如何用fetchpriority把LCP拉回绿区?

去年接手一个卖充电宝和数据线的3C配件独立站,面向北美市场。商品详情页LCP长期在3.4秒上下,移动端更差,一直停在核心网页指标的橙区。团队先怀疑图片太大,压了一轮WebP,从280KB压到90KB,LCP只降了0.3秒,因为瓶颈在下载时机,不在文件大小。

看瀑布图,问题很清楚:主图的下载排在两个第三方脚本和一个评价插件后面,起步晚了将近900毫秒。浏览器没识别出它是LCP,给了Low优先级。

改动只有两处。第一,给主图加fetchpriority=high,并确认它没有被误设成懒加载。第二,把两个第三方脚本从同步改成defer,给评价插件的图加上fetchpriority=low。复测结果:主图下载起点提前到200毫秒以内,LCP降到1.6秒,进入绿区。

全部改动不到十行,没有降低任何一张图的画质。客户当时还问是不是换了服务器,其实没换,只是让浏览器先下载该先下载的资源。

fetchpriority解决的是加载时机这一层,不是全部。那个3C站后来想把LCP再往下压,就不能只靠优先级,还得处理缓存、服务器响应这些更底层的环节,具体拆解见怎么用六层架构把LCP从四秒压到一秒半的那篇复盘。顺序上,先用fetchpriority这种零成本手段消除时机上的浪费,再决定要不要做更重的改造,不要一开始就改服务器。

loading=lazy和fetchpriority有什么区别?懒加载该用在哪些图上?

这两个属性经常被混淆,但管的是两件事。fetchpriority决定要下载的资源之间谁先谁后,loading=lazy决定这张图现在要不要下载。前者排序,后者决定下不下。

loading=lazy会把屏幕外、需要滚动才看得到的图,推迟到快滚到时才下载,省掉首屏用不上的流量,适合长列表和商品瀑布流。这里有个代价很大的误用:首屏图,尤其是LCP图,绝不能挂lazy。一旦挂上,浏览器就会老老实实等到滚动判定才下载,LCP主图直接被推迟,得不偿失。

正确的分工是:首屏图用fetchpriority=high提前下载,明确位于首屏之外的图用loading=lazy延后下载,各管一段。爬虫如何对待这些加载提示是另一个容易出错的点,Googlebot为什么常常不理会资源提示的那篇里专门分析过。简单说,这些提示主要改善真实用户的体验,不要指望它直接改变抓取。

decoding=async和fetchpriority是什么关系?

decoding也常和fetchpriority一起出现,值一般写async。两者作用在不同阶段:fetchpriority管图片下载的优先级,decoding管图片下载完之后如何解码并显示。

图片下载到内存后,要解码成像素才能绘制,大图解码可能阻塞主线程。decoding=async让解码尽量异步进行,避免解码大图时页面卡顿、交互无响应。

我的搭配是:首屏LCP图用fetchpriority=high,但不要加decoding=async,因为这张图需要尽快同步显示,异步解码反而可能让它晚一点出现。首屏下方那些非关键大图适合加decoding=async,下载不急,解码也不该占用主线程。弄清两个属性各自作用的阶段,比记住语法更有用。

把所有资源都设成fetchpriority=high会有什么后果?

最常见的错误用法是:团队学会fetchpriority=high后,给首屏十几个元素全部加上,希望它们一起提速,结果性能反而变差。

原因在于优先级是相对的。所有资源都插队,等于没人插队:全都是最高优先级,浏览器只好退回自己那套排序,白折腾一遍,还多了维护成本。Priority Hints的官方解释文档说得很直接:它的价值在于制造区分度,让少数真正关键的资源排到前面。区分度被稀释,它就失效了。

我的规则是:high每页最多给两个,而且必须说得清为什么是这两个。low可以多用,它只是给别的资源让路,副作用小。拿不准的就保留auto,交给浏览器,它不了解你的业务,但对通用规律的判断基本可靠。

怎么验证fetchpriority真的生效了?用什么工具看?

改完一定要验证,否则浏览器可能根本没采纳你的设置,你却以为已经生效。最直接的方法是看Chrome DevTools的Network面板,其中的Priority列显示每个资源实际拿到的优先级,以及初始优先级和最终优先级是否被调整过。fetchpriority=high有没有生效,看这一列就能确认,比看瀑布图更快。

需要更细的数据时,可以用Performance面板录制一次加载,检查LCP图的下载起点是否提前。Chrome官方那篇讲怎么在DevTools里调试fetch priority的博客详细说明了面板怎么读、每列看什么,按步骤操作即可。

浏览器支持方面,主流浏览器都已支持fetchpriority,Safari也在较新版本中跟进,具体版本可查caniuse上fetchpriority的兼容性表。个别老浏览器不识别时只会忽略这个属性,不报错,也不影响页面,属于可以优雅降级的特性。

fetchpriority和preload资源提示如何分工?

preload、preconnect这类资源提示常和fetchpriority放在一起讨论,但它们解决的问题不在同一层。

资源提示解决发现问题:让浏览器提前知道某个资源会用到,不必等解析到那一行才发现。fetchpriority解决排序问题:在浏览器已知要下载的资源里调整先后。前者管知道得早不早,后者管知道之后谁先下。

两者可以叠加使用:对于写在CSS里、浏览器发现得晚的关键字体,先用preload让它被提前发现,再加fetchpriority=high让它排到前面,效果最好。preload、preconnect、prefetch等资源提示各自的用途,可以看专讲五种资源提示技术对比的指南。资源提示是这类优化的基础,fetchpriority在此之上再做一层调整。

常见问题解答

fetchpriority=high加了却好像没效果,是什么原因?

先查三件事:一是这张图是否同时加了loading=lazy,lazy会直接压过high;二是它是否为CSS背景图,背景图本来起步就晚,fetchpriority起不了作用;三是是否给太多元素设了high,稀释了区分度。在DevTools的Network面板查看Priority列,可以确认浏览器实际给出的优先级。

fetchpriority是排名因素吗?会直接影响SEO吗?

它不是直接的排名信号。但它能实际改善LCP,而LCP是核心网页指标之一,属于页面体验信号。所以它的作用是间接的:优化加载时机,改善核心网页指标,进而对排名和真实用户体验都有帮助。不要指望加个属性排名就变化,应看它带来的指标变化。

一个页面该给几张图设fetchpriority=high?

通常只给一张,就是首屏的LCP元素,最多再加一个首屏必需的关键字体或图标,一般不超过两个。high设得越多越没有意义,全部设成high等于没设。

fetchpriority和preload该用哪个,还是都用?

看场景。如果浏览器很早就能发现这个资源(比如首屏img标签直接写在HTML里),一个fetchpriority=high就够了。如果资源藏得深、发现得晚(比如CSS里引用的字体),就用preload让它被提前发现,再加fetchpriority=high排到前面,两个一起用效果最好。

老浏览器不支持fetchpriority,会不会出问题?

不会。不识别这个属性的浏览器会直接忽略它,页面照常渲染,只是少了这一层优化,不会报错,也不会白屏。这属于渐进增强,可以优雅降级,放心使用,不需要为兼容性写额外的兜底代码,也不用做浏览器判断。

decoding=async该不该给首屏LCP图加?

一般不加。首屏LCP图需要尽快同步显示,异步解码反而可能让它晚一点出现。decoding=async更适合首屏下方那些不急、尺寸又较大的图,避免它们的解码占用主线程。首屏主图用fetchpriority=high提前下载即可,解码交给浏览器同步处理。

权威参考资料

分享到
标签
版权声明

本文标题:《fetchpriority资源优先级详解:浏览器加载排序与懒加载配合实战》

本文链接:https://zhangwenbao.com/fetchpriority-priority-hints-resource-loading-optimization.html

版权声明:本文原创,转载与引用请注明作者与原文链接。许可协议: CC BY 4.0

继续阅读
发表评论
分享到微信 或在下方手动填写
支持 Ctrl + Enter 提交