热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Web性能优化:Preload与Prefetch的使用及在Chrome中的优先级

摘要:理解Preload与Prefetch。原文:Web性能优化:Preload,Prefetch的使用及在Chrome中的优先级作者:前端小智Fundebug经授权转载,版权归原


摘要: 理解Preload与Prefetch。



  • 原文:Web 性能优化:Preload,Prefetch的使用及在 Chrome 中的优先级

  • 作者:前端小智

Fundebug经授权转载,版权归原作者所有。

这是 Web 性能优化的第 6 篇,上一篇在下面看点击查看:



  • Web 性能优化:使用 Webpack 分离数据的正确方法

  • Web 性能优化:图片优化让网站大小减少 62%

  • Web 性能优化:缓存 React 事件来提高性能

  • Web 性能优化:21种优化CSS和加快网站速度的方法

  • Web 性能优化:理解及使用 Javascript 缓存

今天,我们将深入研究Chrome 的网络栈,以明确 web 加载原语(如<link rel= preload > & ) 背后的工作原理,以便你能够更有效地使用它们。

如其他文章所述,preload 是一个声明式 fetch,可以强制浏览器在不阻塞 document 的 onload 事件的情况下请求资源。

Prefetch 告诉浏览器这个资源将来可能需要,但是什么时间加载这个资源是由浏览器来决定的。

在预加载(perload)之前,网络请求从这里开始,预加载之后,它在解析时从左向右移动


使用预加载(perload)的一些案例

在详细介绍 预加载(perload) 之前,先来看看一些使用 预加载(perload) 的案例。

Housing.com 在对他们的渐进式 Web 应用程序的脚本转用 proload 看到大约缩短了10%的可交互时间。

Shopify 使用 [preload 加载 Web字体](https://www.bramstein.com/writing/preload-hints-for-web-fo

nts.html)后,Chrome 桌面版)的文本绘制时间(1.2秒)提高了50%,这完全解决了他们的文字闪动问题。

左边:使用 preload,右边:不使用 preload

使用 加载字体

Treebo,印度最大的旅馆网站之一,在 3G 网络下对其桌面版试验,在对其顶部图片和主要的 Webpack 打包文件使用 preload 之后,在首屏绘制和可交互延迟分别减少了 1s。

同样的,在对自己的渐进式 Web 应用程序主要打包文件使用 preload 之后,Flipkart 在路由解析之前 节省了大量的主线程空闲时间(在 3G 网络下的低性能手机下)。

上面:没有使用 proload 加载,下面:使用 preload 加载

Chrome 数据保护程序团队发现,对于那些可以在脚本和 CSS 样式表上使用 preload 的页面,发现页面首次绘制时间获得平均 12% 的速度提升。

对于 prefetch(预读取),它被广泛使用,在 Google 我们仍用它来预读取一些可以加快 搜索结果页面 的渲染的关键资源。

Preload 在大型网站中都有很好运用,你可以在本文后面找到更多这些安全。 在此之前,让我们深入了解网络堆栈如何实际处理 预加载(prefetch)与预读取(prefetch)


何时使用 和 ?


提示:preload 加载资源一般是当前页面需要的,prefetch 一般是其它页面有可能用到的资源。


preload 是告诉浏览器预先请求当前页面需要的资源(关键的脚本,字体,主要图片等)。

prefetch 应用场景稍微又些不同 —— 用户将来可能跳转到其它页面需要使用到的资源。如果 A 页面发起一个 B 页面的 prefetch 请求,这个资源获取过程和导航请求可能是同步进行的,而如果我们用 preload 的话,页面 A 离开时它会立即停止。

preloadprefetch 之间,我们对当前页面或即将跳转的页面在所需主要资源的问题有了一个解决方案。


和 的缓存行为

当资源被 preload 或者 prefetch 后,会从网络堆栈传输到 HTTP 缓存并进入渲染器的内存缓存。 如果资源可以被缓存(例如,存在有效的 cache-control 和 max-age),它将存储在 HTTP 缓存中,可用于当前和未来的会话。 如果资源不可缓存,则不会将其存储在 HTTP 缓存中。 相反,它会被缓存到内存缓存中并保持不变直到它被使用。


Chrome 的网络栈中是如何处理 preload 和 prefetch 的优先级?

下面是在 Blink 内核的 Chrome 46 及更高版本中不同资源的加载优先级情况著作权归作者所有。


preload 用 “as” 或者用 “type” 属性来表示他们请求资源的优先级(比如说 preload 使用 as=“style” 属性将获得最高的优先级)。没有 “as” 属性的将被看作异步请求,“Early”意味着在所有未被预加载的图片请求之前被请求(“late”意味着之后)


我们来谈一下这张表。

脚本根据它们在文件中的位置是否异步、延迟或阻塞获得不同的优先级:



  • 网络在第一个图片资源之前阻塞的脚本在网络优先级中是中级

  • 网络在第一个图片资源之后阻塞的脚本在网络优先级中是低级

  • 异步/延迟/插入的脚本(无论在什么位置)在网络优先级中是很低级

图像在可视窗口中比不在视口中的图像(具有更高的优先级,因此在某种程度上, Chrome 将会尽量懒加载这些不在视口中的图片。 较低优先级的图片出现在视口中时,该图片的优先级就会得到提升(但是注意已经在布局完成后的图片优先级不会在更改)。

使用“as”属性预加载的资源将具有与它们请求的资源类型相同的资源优先级。 例如,preload as =“style”将获得最高优先级,而as =“script”将获得低优先级或中优先级。 这些资源也遵循相同的CSP策略(例如脚本受 script-src 约束)。

不带 “as” 属性的 preload 的优先级将会等同于异步请求。

如果你想了解各种资源加载时的优先级属性,从开发者工具的 Timeline/Performance 区域的 Network 区域都能看到相关信息:

在 Network 面板下的 “Priority” 部分


当页面 preload 已经在 Service Worker 缓存及 HTTP 缓存中的资源时会发生什么?

这各情况来说是比较少的,但通常来说,会是比较好的情况 —— 如果资源没有超出 HTTP 缓存时间或者 Service Worker 没有主动重新发起请求,那么浏览器就不会再去请求这个资源了。

如果资源在 HTTP 缓存中(在SW缓存和网络之间),那么 preload 会从相同的资源中获得缓存命中。


这种加载方式会浪费用户的带宽吗

使用 preload 或 prefetch,可能会浪费用户的带宽,特别是在资源没有缓存的情况下。

没有用到的 preload 资源在 Chrome 的 console 里会在 onl oad 事件 3s 后发生警告。

这个警告的原因是,你可能正在使用preload来尝试为其他资源预加载并缓存以提高性能,但是如果这些预加载的资源没有被使用,那么你就在毫无理由地做额外的工作。在移动设备上,这相当于浪费用户的流量,所以要注意预加载的内容。


什么情况会导致二次获取?

preloadprefetch 是很简单的工具,你很容易不小心二次获取。

不要用 “prefetch” 作为 “preload” 的后备方案 ,它们适用于不同的场景,常常会导致不符合预期的二次获取。使用 preload来获取当前需要任务否则使用 prefetch 来获取将来的任务,不要一起用。

对 preload 使用 “as” 属性,不然将不会从中获益。

如果在指定要 preload 的内容(例如脚本)时未提供有效的“as”,则最终将获取两次。

preload 字体不带 crossorigin 也将会二次获取, 确保在使用 preload 获取字体时添加crossorigin 属性,否则将二次下载。 他这个请求使用匿名的跨域模式。 即使字体与页面位于同个域 下,也建议使用。也适用于其他域名的获取(比如说默认的异步获取)。

最后,虽然它不会导致两次获取,但这通常是一个很好的建议:

不要所有的请求资源都加 preload,用 preload 来告诉浏览器一些很被需要的资源,以便让它提早获取它们。


我应当在页面头部所有的资源都加上 preload

这是工具的一个很好的例子,而不是规则。 preload 的文件数量取决于加载其他资源时网络内容、用户的带宽和其他网络状况。

尽早 preload 页面中可能需要的文件,对于脚本,preload 你的密钥包是很好的,因为它将获取与执行分开,而仅仅使用 不会这样做,因为它会阻止窗口的 onload 事件。你可以 preload 图像、样式、字体和媒体。最重要的是,作为一名页面作者,你可以更好地控制提前获取页面所需要的信息。


prefetch 是否具有你应该注意的任何魔法属性? 是的,

在 Chrome 中,如果用户导航离开一个页面,而对其他页面的预取请求仍在进行中,这些请求将不会被终止。

此外,无论资源的可缓存性如何,prefetch 请求在未指定的网络堆栈缓存中至少保存 5 分钟。


我在 JS 中使用自定义的 “preload”,它跟原本的 rel=“preload” 或者 preload 头部有什么不同?

preload 解耦从 JS 处理和执行中获取资源。 因此,preload 在标记中声明以被 Chrome preload 扫描器扫描。 这意味着在许多情况下,在 HTML 解析器甚至到达标签之前,将获取预加载(具有指示的优先级),这使它比自定义预加载实现更强大。

代码部署后可能存在的BUG没法实时知道,事后为了解决这些BUG,花了大量的时间进行log 调试,这边顺便给大家推荐一个好用的BUG监控工具 Fundebug。


不是可以用 HTTP/2 的服务器推送来代替 preload 吗?

当你知道资源的精确加载顺序时使用推送,并让 service worker 拦截可能导致再次推送缓存资源的请求。 使用 preload 可以使资源的开始下载时间更接近初始请求 - 这对所有的资源获取都有用。

我们假设浏览器正在加载一个页面,页面中有个 CSS 文件,CSS 文件又引用一个字体库,对于这样的场景,

若使用 HTTP/2 PUSH,当服务端获取到 HTML 文件后,知道以后客户端会需要字体文件,它就立即主动地推送这个文件给客户端,如下图:

而对于 preload,服务端就不会主动地推送字体文件,在浏览器获取到页面之后发现 preload 字体才会去获取,如下图:

虽然推送很有效,但它不像 preload 那样对所有的情况都适应。

推送不能用于第三方资源的内容,通过立即发送资源,它还有效地缩短浏览器自身的资源优先级情况。在你明确的知道在做什么时,这应该会提高你的应用性能,如果不是很清晰的话,你也许会损失掉部分的性能。


peload 请求头是什么?它与 preload 标签相比如何?它与 HTTP/2 服务器推送有什么关系?

与其他类型的链接一样,preload 链接即可以使用 HTML标记 或 HTTP标头。 在任何一种情况下,preload 链接都会指示浏览器开始将资源加载到内存缓存中,这表明该页面有很高可能性使用该资源,并且不希望等待预加载扫描程序或解析程序发现它。

当金融时报在它们的网站使用 preload HTTP 头时,他们节约了大约 1s 的显示片头图片时间。

1: 没有使用 preload 2:使用了 preload

你可以使用任何一种形式提供 preload 链接,但是你应该知道一个重要区别:如规范所允许的,许多服务器在遇到 HTTP 头的 preload 链接时会触发 HTTP/2 服务器推送。 HTTP/2 推送的性能影响不同于普通的预加载,所以你要确保没有发起不必要的推送。

你可以使用 preload 标签来代替 preload 头以避免不必要的推送,或者在你的 HTTP 头上加一个 “nopush” 属性。


如何判断 的支持情况?

以下的代码段可以判断 支持情况:

const preloadSupported = () => {
const link = document.createElement('link');
const relList = link.relList;
if (!relList || !relList.supports)
return false;
return relList.supports('preload');
};

FilamentGroup 也有一个 preload 检测器 ,作为他们的异步 CSS 加载库 loadCSS 的一部分。


可以使用 preload 让CSS样式立即生效吗?

当然可以,preload 支持基于异步加载的标记,使用 的样式表可以使用 onload 事件立即应用于当前文档:



preload 还被哪些网站广泛的应用?

根据 HTTPArchive,大多数使用 的网站使用它来预加载Web字体,包括 Teen Vogue 和前面提到的 Shopify

而 LifeHacker 和 JCPenny 等其他热门网站使用它来异步加载CSS(通过Filament Group loadCSS):

然后,有越来越多的渐进式 Web 应用程序(如 Twitter.com mobile、Flipkart 和Housing)使用它来预加载当前导航所需的脚本(使用PRPL等模式)

其基本思想是以高粒度维护工件(而不是整体捆绑),所以任何应用都可以按需加载依赖或者预加载资源并放在缓存中。


当前浏览器对 preload 和 Prefetch 的支持程序如何

根据 CanIUse,约 50% 的支持度, 约 71%。


相关阅读



  • Preload — what is it good for? — Yoav Weiss

  • A study by the Chrome Data Saver team

  • Planning for performance — Sam Saccone

  • Webpack plugin for auto-wiring up

  • What is preload, prefetch and preconnect? — KeyCDN

  • Web Fonts preloaded by Zach Leat

  • HTTP Caching: cache-control by Ilya Grigorik


关于Fundebug

Fundebug专注于Javascript、微信小程序、微信小游戏、支付宝小程序、React Native、Node.js和Java线上应用实时BUG监控。 自从2016年双十一正式上线,Fundebug累计处理了10亿+错误事件,付费客户有Google、360、金山软件、百姓网等众多品牌企业。欢迎大家免费试用!



推荐阅读
  • 如何查询zone下的表的信息
    本文介绍了如何通过TcaplusDB知识库查询zone下的表的信息。包括请求地址、GET请求参数说明、返回参数说明等内容。通过curl方法发起请求,并提供了请求示例。 ... [详细]
  • Imtryingtofigureoutawaytogeneratetorrentfilesfromabucket,usingtheAWSSDKforGo.我正 ... [详细]
  • SpringBoot uri统一权限管理的实现方法及步骤详解
    本文详细介绍了SpringBoot中实现uri统一权限管理的方法,包括表结构定义、自动统计URI并自动删除脏数据、程序启动加载等步骤。通过该方法可以提高系统的安全性,实现对系统任意接口的权限拦截验证。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • C# 7.0 新特性:基于Tuple的“多”返回值方法
    本文介绍了C# 7.0中基于Tuple的“多”返回值方法的使用。通过对C# 6.0及更早版本的做法进行回顾,提出了问题:如何使一个方法可返回多个返回值。然后详细介绍了C# 7.0中使用Tuple的写法,并给出了示例代码。最后,总结了该新特性的优点。 ... [详细]
  • 本文介绍了Windows操作系统的版本及其特点,包括Windows 7系统的6个版本:Starter、Home Basic、Home Premium、Professional、Enterprise、Ultimate。Windows操作系统是微软公司研发的一套操作系统,具有人机操作性优异、支持的应用软件较多、对硬件支持良好等优点。Windows 7 Starter是功能最少的版本,缺乏Aero特效功能,没有64位支持,最初设计不能同时运行三个以上应用程序。 ... [详细]
  • 基于Axis、XFire、CXF的webservice客户端调用示例
    本文介绍了如何使用Axis、XFire、CXF等工具来实现webservice客户端的调用,以及提供了使用Java代码进行调用的示例。示例代码中设置了服务接口类、地址,并调用了sayHello方法。 ... [详细]
  • 本文介绍了OpenStack的逻辑概念以及其构成简介,包括了软件开源项目、基础设施资源管理平台、三大核心组件等内容。同时还介绍了Horizon(UI模块)等相关信息。 ... [详细]
  • 模板引擎StringTemplate的使用方法和特点
    本文介绍了模板引擎StringTemplate的使用方法和特点,包括强制Model和View的分离、Lazy-Evaluation、Recursive enable等。同时,还介绍了StringTemplate语法中的属性和普通字符的使用方法,并提供了向模板填充属性的示例代码。 ... [详细]
  • 本文记录了在vue cli 3.x中移除console的一些采坑经验,通过使用uglifyjs-webpack-plugin插件,在vue.config.js中进行相关配置,包括设置minimizer、UglifyJsPlugin和compress等参数,最终成功移除了console。同时,还包括了一些可能出现的报错情况和解决方法。 ... [详细]
  • 本文讨论了编写可保护的代码的重要性,包括提高代码的可读性、可调试性和直观性。同时介绍了优化代码的方法,如代码格式化、解释函数和提炼函数等。还提到了一些常见的坏代码味道,如不规范的命名、重复代码、过长的函数和参数列表等。最后,介绍了如何处理数据泥团和进行函数重构,以提高代码质量和可维护性。 ... [详细]
  • 本文介绍了使用哈夫曼树实现文件压缩和解压的方法。首先对数据结构课程设计中的代码进行了分析,包括使用时间调用、常量定义和统计文件中各个字符时相关的结构体。然后讨论了哈夫曼树的实现原理和算法。最后介绍了文件压缩和解压的具体步骤,包括字符统计、构建哈夫曼树、生成编码表、编码和解码过程。通过实例演示了文件压缩和解压的效果。本文的内容对于理解哈夫曼树的实现原理和应用具有一定的参考价值。 ... [详细]
  • 本文整理了Java面试中常见的问题及相关概念的解析,包括HashMap中为什么重写equals还要重写hashcode、map的分类和常见情况、final关键字的用法、Synchronized和lock的区别、volatile的介绍、Syncronized锁的作用、构造函数和构造函数重载的概念、方法覆盖和方法重载的区别、反射获取和设置对象私有字段的值的方法、通过反射创建对象的方式以及内部类的详解。 ... [详细]
  • 本文介绍了使用Spark实现低配版高斯朴素贝叶斯模型的原因和原理。随着数据量的增大,单机上运行高斯朴素贝叶斯模型会变得很慢,因此考虑使用Spark来加速运行。然而,Spark的MLlib并没有实现高斯朴素贝叶斯模型,因此需要自己动手实现。文章还介绍了朴素贝叶斯的原理和公式,并对具有多个特征和类别的模型进行了讨论。最后,作者总结了实现低配版高斯朴素贝叶斯模型的步骤。 ... [详细]
  • 代理模式的详细介绍及应用场景
    代理模式是一种在软件开发中常用的设计模式,通过在客户端和目标对象之间增加一层中间层,让代理对象代替目标对象进行访问,从而简化系统的复杂性。代理模式可以根据不同的使用目的分为远程代理、虚拟代理、Copy-on-Write代理、保护代理、防火墙代理、智能引用代理和Cache代理等几种。本文将详细介绍代理模式的原理和应用场景。 ... [详细]
author-avatar
男人着责任
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有