阿里云最近在作活动,低至2折,有兴趣能够看看:
https://promotion.aliyun.com/...
为了保证的可读性,本文采用意译而非直译。css
这是 Web 性能优化的第 6 篇,上一篇在下面看点击查看:html
今天,咱们将深刻研究Chrome 的网络栈,以明确 web 加载原语(如<link rel= preload >
& <link rel= prefetch >
) 背后的工做原理,以便你可以更有效地使用它们。前端
想阅读更多优质文章请猛戳GitHub博客,一年百来篇优质文章等着你!webpack
如其余文章所述,preload 是一个声明式 fetch
,能够强制浏览器在不阻塞 document
的 onload 事件的状况下请求资源。git
Prefetch
告诉浏览器这个资源未来可能须要,可是什么时间加载这个资源是由浏览器来决定的。github
在预加载(perload)以前,网络请求从这里开始,预加载以后,它在解析时从左向右移动web
在详细介绍 预加载(perload) 以前,先来看看一些使用 预加载(perload) 的案例。chrome
Housing.com 在对他们的渐进式 Web 应用程序的脚本转用 proload 看到大约缩短了10%的可交互时间。segmentfault
Shopify 使用 preload 加载 Web字体后,Chrome 桌面版)的文本绘制时间(1.2秒)提升了50%,这彻底解决了他们的文字闪动问题。跨域
左边:使用 preload,右边:不使用 preload
使用<link rel=”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 离开时它会当即中止。
在 preload
和 prefetch
之间,咱们对当前页面或即将跳转的页面在所需主要资源的问题有了一个解决方案。
当资源被 preload
或者 prefetch
后,会从网络堆栈传输到 HTTP 缓存并进入渲染器的内存缓存。 若是资源能够被缓存(例如,存在有效的 cache-control 和 max-age),它将存储在 HTTP 缓存中,可用于当前和将来的会话。 若是资源不可缓存,则不会将其存储在 HTTP 缓存中。 相反,它会被缓存到内存缓存中并保持不变直到它被使用。
下面是在 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” 部分
这各状况来讲是比较少的,但一般来讲,会是比较好的状况 —— 若是资源没有超出 HTTP 缓存时间或者 Service Worker 没有主动从新发起请求,那么浏览器就不会再去请求这个资源了。
若是资源在 HTTP 缓存中(在SW缓存和网络之间),那么 preload
会从相同的资源中得到缓存命中。
使用 preload 或 prefetch,可能会浪费用户的带宽,特别是在资源没有缓存的状况下。
没有用到的 preload
资源在 Chrome 的 console
里会在 onload 事件 3s 后发生警告。
这个警告的缘由是,你可能正在使用preload
来尝试为其余资源预加载并缓存以提升性能,可是若是这些预加载的资源没有被使用,那么你就在毫无理由地作额外的工做。在移动设备上,这至关于浪费用户的流量,因此要注意预加载的内容。
preload
和 prefetch
是很简单的工具,你很容易不当心二次获取。
不要用 “prefetch” 做为 “preload” 的后备方案 ,它们适用于不一样的场景,经常会致使不符合预期的二次获取。使用 preload
来获取当前须要任务不然使用 prefetch
来获取未来的任务,不要一块儿用。
对 preload 使用 “as” 属性,否则将不会从中获益。
若是在指定要 preload
的内容(例如脚本)时未提供有效的“as”
,则最终将获取两次。
preload 字体不带 crossorigin 也将会二次获取, 确保在使用 preload
获取字体时添加crossorigin
属性,不然将二次下载。 他这个请求使用匿名的跨域模式。 即便字体与页面位于同个域 下,也建议使用。也适用于其余域名的获取(好比说默认的异步获取)。
最后,虽然它不会致使两次获取,但这一般是一个很好的建议:
不要全部的请求资源都加 preload,用 preload
来告诉浏览器一些很被须要的资源,以便让它提前获取它们。
preload
?这是工具的一个很好的例子,而不是规则。 preload
的文件数量取决于加载其余资源时网络内容、用户的带宽和其余网络情况。
尽早 preload
页面中可能须要的文件,对于脚本,preload
你的关键模块是很好的,由于它将获取与执行分开,而仅仅使用 <script async>
不会这样作,由于它会阻止窗口的 onload
事件。你能够 preload
图像、样式、字体和媒体。最重要的是,做为一名页面做者,你能够更好地控制提早获取页面所须要的信息。
在 Chrome 中,若是用户导航离开一个页面,而对其余页面的预取请求仍在进行中,这些请求将不会被终止。
此外,不管资源的可缓存性如何,prefetch
请求在未指定的网络堆栈缓存中至少保存 5 分钟。
preload
解耦从 JS 处理和执行中获取资源。 所以,preload 在标记中声明以被 Chrome preload 扫描器扫描。 这意味着在许多状况下,在 HTML 解析器甚至到达标签以前,将获取预加载(具备指示的优先级),这使它比自定义预加载实现更强大。
当你知道资源的精确加载顺序时使用推送,并让 service worker 拦截可能致使再次推送缓存资源的请求。 使用 preload
可使资源的开始下载时间更接近初始请求 - 这对全部的资源获取都有用。
咱们假设浏览器正在加载一个页面,页面中有个 CSS 文件,CSS 文件又引用一个字体库,对于这样的场景,
若使用 HTTP/2 PUSH,当服务端获取到 HTML 文件后,知道之后客户端会须要字体文件,它就当即主动地推送这个文件给客户端,以下图:
而对于 preload,服务端就不会主动地推送字体文件,在浏览器获取到页面以后发现 preload 字体才会去获取,以下图:
虽然推送颇有效,但它不像 preload
那样对全部的状况都适应。
推送不能用于第三方资源的内容,经过当即发送资源,它还有效地缩短浏览器自身的资源优先级状况。在你明确的知道在作什么时,这应该会提升你的应用性能,若是不是很清晰的话,你也许会损失掉部分的性能。
与其余类型的连接同样,preload 连接便可以使用 HTML标记 或 HTTP标头。 在任何一种状况下,preload 连接都会指示浏览器开始将资源加载到内存缓存中,这代表该页面有很高可能性使用该资源,而且不但愿等待预加载扫描程序或解析程序发现它。
当金融时报在它们的网站使用 preload HTTP 头时,他们节约了大约 1s 的显示片头图片时间。
1: 没有使用 preload 2:使用了 preload
你可使用任何一种形式提供 preload 连接,可是你应该知道一个重要区别:如规范所容许的,许多服务器在遇到 HTTP 头的 preload 连接时会触发 HTTP/2 服务器推送。 HTTP/2 推送的性能影响不一样于普通的预加载,因此你要确保没有发起没必要要的推送。
你可使用 preload 标签来代替 preload 头以免没必要要的推送,或者在你的 HTTP 头上加一个 “nopush” 属性。
如下的代码段能够判断 <link rel=”preload”>
支持状况:
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 支持基于异步加载的标记,使用 <link rel=”preload”>
的样式表可使用 onload
事件当即应用于当前文档:
<link rel="preload" href="style.css" onload="this.rel=stylesheet">
根据 HTTPArchive,大多数使用 <link rel =“preload”>
的网站使用它来预加载Web字体,包括 Teen Vogue 和前面提到的 Shopify:
而 LifeHacker 和 JCPenny 等其余热门网站使用它来异步加载CSS(经过Filament Group loadCSS):
而后,有愈来愈多的渐进式 Web 应用程序(如 Twitter.com mobile、Flipkart 和Housing)使用它来预加载当前导航所需的脚本(使用PRPL等模式)
其基本思想是以高粒度维护工件(而不是总体捆绑),因此任何应用均可以按需加载依赖或者预加载资源并放在缓存中。
根据 CanIUse,<link rel =“preload”>
约 50% 的支持度, <link rel =“prefetch”>
约 71%。
代码部署后可能存在的BUG无法实时知道,过后为了解决这些BUG,花了大量的时间进行log 调试,这边顺便给你们推荐一个好用的BUG监控工具 Fundebug。
你的点赞是我持续分享好东西的动力,欢迎点赞!
干货系列文章汇总以下,以为不错点个Star,欢迎 加群 互相学习。
https://github.com/qq44924588...
我是小智,公众号「大迁世界」做者,对前端技术保持学习爱好者。我会常常分享本身所学所看的干货,在进阶的路上,共勉!
关注公众号,后台回复福利,便可看到福利,你懂的。