A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

奇技指南
今天给大家介绍一个性能优化利器:Preload。
本文作者是来自奇舞团的前端工程师黄小璐,同时是W3C性能工作组成员。
背景
有时候为了提高网页初始加载的性能,我们会选择延迟一部分资源的加载和执行。
另一种情况是我们想要尽早加载资源,但是要等到合适的时机再执行。时机的影响因素包括依赖关系、执行条件、执行顺序等。
通常的做法是:
  • 通过插入一个页面元素来声明一个资源(比如img、script、link)。这种方式会将资源的加载和执行耦合。
  • 用AJAX来加载资源。这种方式只有在时机成熟时才会加载资源,解决了执行时机问题。但是浏览器无法预解析,也就无法提前加载。另外如果页面有大量的阻塞脚本,就会造成延迟。

有没有办法既提前加载资源,又能解耦加载和执行呢?这时候就轮到preload大显身手啦。
什么是Preload
preload是一个预加载关键字。它显式地向浏览器声明一个需要提前加载的资源。使用方式如下:
  • 在<head>中写入 <link rel="preload" href="some-resource-url" as="xx">(包括用JS创建<link>元素并插入到 <head>)
  • 在HTTP头部加上Link: <some-resource-url>; rel=preload; as=xx

当浏览器“看”到这样的声明后,就会以一定的优先级在后台加载资源。加载完的资源放在HTTP缓存中。而等到要真正执行时,再按照正常方式用标签或者代码加载,即可从HTTP缓存取出资源。
使用Preload加载资源的方式有以下几个特点:
  • 提前加载资源
  • 资源的加载和执行分离
  • 不延迟网页的load事件(除非Preload资源刚好是阻塞 window 加载的资源)

大家可能会问:Preload跟其他提前加载资源以及加载和执行分离的方案有什么区别?
好的,满足你们的好奇心:
vs. 预测解析
浏览器很聪明,它可以在解析 HTML 时收集外链资源。并将它们添加到一个列表,在后台并行下载。预测解析也实现了提前加载以及加载和执行分离。如图所示:
那么它跟Preload的区别是什么?
  • 仅限于解析HTML时收集的外链资源。如果是程序里异步加载的资源无法提前收集到。
  • 浏览器不暴露类似于Preload中的onload事件,也就无法更细粒度控制资源的执行。

vs. async
async 脚本是一加载完就立即执行,因此会阻塞window的onload事件。而且目前async仅限于脚本资源。
Preload可以实现async一样的异步加载功能。且不局限于脚本。比如以下代码实现了加载完CSS文件立即作用到网页的功能:
<link rel="preload" href="style.css" as="style" onload="this.rel='stylesheet'">
注:如果页面存在同步阻塞脚本,等脚本执行完后,样式才会作用到网页。这样是因为Preload的资源不会阻塞window的onload事件。
vs. defer
defer实现了资源的加载和执行分离,并且它能保证 defer的资源按照在HTML里的出现顺序执行。跟async一样,目前也只能作用于脚本资源。
Preload则适用多种资源类型。Preload的资源也能像defer的资源一样延迟执行并保证执行顺序。
vs. Sever Push
HTTP/2的Server Push也实现了资源的提前加载以及加载执行分离。不过Server Push节省了一个网络来回。我们可以结合Server Push优化Preload,比如服务器识别到文档里的Preload的资源就主动推送Preload的资源。
如果不希望服务器推送,则可以增加nopush属性:
Link: </app/style.css>; rel=preload; as=style; nopush
另外Server Push只能推送同域资源。而Preload则可以支持跨域资源。
何时使用Preload
任何你想要先加载后执行,或者想要提高页面渲染性能的场景都可以使用Preload。
典型用例:
  • 在单页应用中,提前加载路由文件,提高切换路由时的渲染速度。现在大型的单页应用通常会异步加载路由文件。当用户切换路由时再异步加载相应的模块存在性能问题。可以用Preload提前加载,提升性能。
  • 提前加载字体文件。由于字体文件必须等到CSSOM构建完成并且作用到页面元素了才会开始加载,会导致页面字体样式闪动(FOUT,Flash of Unstyled Text)。所以要用Preload显式告诉浏览器提前加载。假如字体文件在CSS生效之前下载完成,则可以完全消灭FOUT。

浏览器兼容性
Preload的兼容性如下:
截至本文写作时,在PC上实现了Preload的浏览器包括: Chrome 50+,Saferi 11.1+ 。Edge 17+支持HTML  方式,不支持HTTP header方式。移动端:iOS Safari 11.4+,Android Chrome 67
不支持Preload的浏览器会自动忽略它,并采用普通的加载方式。因此可以将此功能作为一种渐进增强方式用到我们的网页应用中。
鸣谢
何文力和李松峰对文章的内容和细节提出了宝贵的修订意见,感谢!
参考链接
  • https://www.w3.org/TR/preload/
  • https://developer.mozilla.org/zh-CN/docs/Web/HTML/Preloading_content
  • https://www.jianshu.com/p/24ffa6d45087
  • https://yoavweiss.github.io/link_htmlspecial_16
  • https://www.w3cplus.com/javascript/building-the-dom-faster-speculative-parsing-async-defer-and-preload.html

界世的你当不
只作你的肩膀

1 个回复

倒序浏览
奈斯
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马