2018 前端性能优化清单 - 第 3 部分

下面你将会看到你可能须要考虑到的前端性能优化问题,以保证你的应用具备快速和流畅的响应时间。css


静态资源优化

  1. 你是使用 Brotli 仍是 Zopfli 进行纯文本压缩?

在 2005 年,Google 推出了 Brotli,一个新的开源无损数据压缩格式,如今 被全部的现代浏览器所支持。实际上,Brotli 比 Gzip 和 Deflate 更有效。取决于设置信息,压缩可能会很是慢。可是缓慢的压缩过程会提升压缩率,而且仍然能够快速解压。固然,解压缩速度很快。html

只有当用户经过 HTTPS 访问网站时,浏览器才会采用。Brotli 如今还不能预装在某些服务器上,并且若是不本身构建 NGINX 和 UBUNTU 的话很难部署。不过这也并不难。实际上,一些 CDN 是支持的,甚至 能够也能够经过服务器在不支持 CDN 的状况下启用 Brotli前端

在最高级别的压缩下,Brotli 的速度会变得很是慢,以致于服务器在等待动态压缩资源时开始发送响应所花费的时间可能会使文件大小的任何潜在收益都无效。可是,对于静态压缩,高压缩比的设置比较受欢迎 —— (感谢 Jeremy!android

或者,你能够考虑使用 Zopfli 的压缩算法,将数据编码为 Deflate,Gzip 和 Zlib 格式。Zopfli 改进的 Deflate 编码使得任何使用 Gzip 压缩的文件受益,由于这些文件大小比 用Zlib 最强压缩后还要小 3% 到 8%。问题在于压缩文件的时间是原来的大约 80倍。这就是为何虽然 使用 Zopfli 是一个好主意可是变化并不大,文件都须要设计为只压缩一次能够屡次下载的。ios

比较好的方法是你能够绕过动态压缩静态资源的成本。Brotli 和 Zopfli 均可以用于明文传输 —— HTML,CSS,SVG,JavaScript 等。git

有什么方法呢?在最高等级和 Brotli 的 1-4 级动态压缩 HTML 使用 Brotli+Gzip 预压缩静态资源。同时,检查 Brotli 是否支持 CDN,(例如 KeyCDN,CDN77,Fastly)。确保服务器可以使用 Brotli 或 gzip 处理内容。若是你不能安装或者维护服务器上的 Brotli,那么请使用 Zopfli。github

  1. 图像是否进行了适当的优化? 尽量经过 srcsetsizes<picture> 元素使用 响应式图片。也能够经过 <picture> 元素使用 WebP 格式的图像(Chrom,Opera,Firefox soon支持),或者一个 JPEG 的回调(见 Andreas Bovens 的 code snippet)或者经过使用内容协商(使用 Accept 头信息)。

Sketch 自己就支持 WebP 而且 WebP 图像能够经过使用 WebP 插件 从 PhotoShop 中导出。也有其余选择可使用,若是你使用 WordPress 或者 Joomla,也有能够轻松支持 WebP 的扩展,例如 OptimusCache Enabler(经过 Cody Arsenaultweb

你能够仍然使用 client hints,但仍须要得到一些浏览器支持。没有足够的资源支持响应式图片?使用 断点发生器 或者相似 Cloudinary 这样的服务自动优化图片。一样,在许多状况下,只使用 srcsetsizes 会有不错的效果。算法

On Smashing Magazine, we use the postfix -opt for image names — for example, brotli-compression-opt.png; whenever an image contains that postfix, everybody on the team knows that the image has already been optimized.chrome

响应图像断点发生器

响应图像断点生成器自动生成图像和标记生成。

  1. 将图像优化到下一个级别 如今有一个相当重要着陆页,有一个特定的图片的加载速度很是关键,确保 JPEGs 是渐进式的而且使用 AdeptmozJPEG (经过操纵扫描级来改善开始渲染时间)或者 Guetzli 压缩,谷歌新的开源编码器重点是可以感官的性能,并借鉴 Zopfli 和 WebP。惟一的 不足 是:处理的时间慢(每百万像素 CPU 一分钟)。至于 png,咱们可使用 Pingo,和 svgo,对于 SVG 的处理,咱们使用 SVGOSVGOMG

每个图像优化的文章会说明,但始终保持保持矢量资产清洁老是值得提醒的。确保清理未使用的资源,删除没必要要的元数据,并减小图稿中的路径点数量(从而减小SVG代码)。(感谢,Jeremy!

到目前为止,这些优化只涵盖了基础知识。 Addy Osmani 已经发布了 一个很是详细的基本图像优化指南,深刻到图像压缩和颜色管理的细节。 例如,您能够模糊图像中没必要要的部分(经过对其应用高斯模糊滤镜)以减少文件大小,最终甚至能够开始移除颜色或将图像变成黑白色,以进一步缩小图像尺寸。 对于背景图像, 从Photoshop 导出的照片质量为 0 到 10% 也是绝对能够接受的。

那么 GIF 图片呢?咱们可使用 循环的 HTML5 视频,而不是影响渲染性能和带宽的重度 GIF 动画,而使用循环的 HTML5 视频,<video> 会使得 浏览器的性能很慢,并且与图像不一样的是,浏览器不会预先加载 <video> 内容。 至少咱们可使用 Lossy GIF, gifsicle 或者 giflossy 添加有损压缩 GIF。

消息: 但愿不久之后咱们可使用 <img src=".mp4"> 来加载视频, 早期的测试代表 img 标签比同等大小的 GIF 显示的要 快 20 多倍解析速度与要快 7 倍多

还不够好?那么,你也可使用 多种 背景 图像 技术 提升图像的感知性能。 记着,减小对比度 和模糊没必要要的细节(或消除颜色)也能够减少文件的大小。 你须要放大一个小照片而不失真?考虑使用 Letsenhance.io

Zach Leatherman的字体加载策略综合指南

Zach Leatherman 的 字体加载策略综合指南 提供了十几种更好的网页字体发送选项

  1. Web字体是否优化? 首先须要问一个问题,你是否能不使用 UI 系统字体。 若是不能够,那么你有很大可能使用 Web 网络字体,会包含字形和额外的功能以及用不到的加粗。 若是您使用的是开源字体(例如,经过仅包含带有某些特殊的重音字形的拉丁语),则能够只选择部分 Web 字体来减小其文件大小。

WOFF2 很是好,你可使用 WOFF 和 OTF 做为不支持它的浏览器的备选。另外,从 Zach Leatherman 的《字体加载策略综合指南》(代码片断也能够做为 Web字体加载片断)中选择一种策略,并使用服务器缓存持久地缓存字体。是否是感受小有成就?Pixel Ambacht 有一个 快速教程和案例研究,让你的字体按顺序排列。

若是你没法从你的服务器拿到字体并依赖于第三方主机,请确保使用 字体加载事件(或对不支持它的浏览器使用 Web字体加载器FOUT 要优于 FOIT; 当即开始渲染文本,并异步加载字体 —— 也可使用 loadCSS。 你也能够 摆脱本地安装的操做系统字体,也可使用 可变的 字体

怎么才能是一个无漏洞的字体加载策略? 从 font-display 开始,而后回到 Font Loading API,而后回到 Bram Stein 的 Font Face Observer感谢 Jeremy!)若是你有兴趣从用户的角度来衡量字体加载的性能, Andreas Marschke 探索了 使用 Font API 和 UserTiming API 进行性能跟踪

此外,不要忘记包含 font-display:optional 描述符来提供弹性和快速的字体回退,unicode-range 将大字体分解成更小的语言特定的字体,以及Monica Dinculescu 的字体样式匹配器 用来解决因为两种字体之间的大小差别,最大限度地减小了布局上的震动的问题。

交付优化

  1. 你是否异步加载 JavaScript? 当用户请求页面时,浏览器获取 HTML 并构造 DOM,而后获取 CSS 并构造 CSSOM,而后经过匹配 DOM 和 CSSOM 生成一个渲染树。若是有任何的 JavaScript 须要解决,浏览器将不会开始渲染页面,直到 JavaScript 解决完毕,这样就会延迟渲染。 做为开发人员,咱们必须明确告诉浏览器不要等待并当即开始渲染页面。 为脚本执行此操做的方法是使用 HTML 中的 deferasync 属性。

事实证实,咱们 应该把 defer 改成 async(由于 ie9 及如下不支持 async)。 另外,如上所述,限制第三方库和脚本的影响,特别是使用社交共享按钮和嵌入的 <iframe> 嵌入(如地图)。 大小限制 有助于防止 JavaScript 库过大:若是您不当心添加了大量依赖项,该工具将通知你并抛出错误。 您可使用 静态社交分享按钮(如经过 SSBG )和 静态连接 来代替交互式地图。

  1. 你是否懒加载了开销很大并使用 Intersection Observer 的代码? 若是您须要延迟加载图片、视频、广告脚本、A/B 测试脚本或任何其余资源,则可使用 Intersection Observer API,它提供了一种方法异步观察目标元素与 祖先元素或顶层文档的视口。基本上,你须要建立一个新的 IntersectionObserver 对象,它接收一个回调函数和一组选项。 而后咱们添加一个目标来观察。

当目标变得可见或不可见时执行回调函数,因此当它拦截视口时,能够在元素变得可见以前开始采起一些行动。 事实上,咱们能够精确地控制观察者的回调什么时候被调用,使用 rootMargin(根边缘)和 threshold(一个数字或者一个数字数组来表示目标可见度的百分比, 瞄准)。Alejandro Garcia Anglada 发表了一个 简单的教程 关于如何实际实施的方便教程。

你甚至能够经过向你的网页添加 渐进式图片加载 来将其提高到新的水平。 与 Facebook,Pinterest 和 Medium 相似,你能够首先加载低质量或模糊的图像,而后在页面继续加载时,使用 Guy Podjarny 提出的 LQIP (Low Quality Image Placeholders) technique(低质量图像占位符)技术替换它们的所有质量版本。

若是技术提升了用户体验,观点就不同了,但它确定会提升第一次有意义的绘画的时间。咱们甚至能够经过使用 SQIP 建立图像的低质量版本做为 SVG 占位符来实现自动化。 这些占位符能够嵌入 HTML 中,由于它们天然能够用文本压缩方法压缩。 Dean Hume 在他的文章中 描述了 如何使用相交观测器来实现这种技术。

浏览器支持成都如何呢?Decent,与 Chrome,火狐,Edge 和 Samsung Internet 已经支持了。 WebKit 目前 正在开发中。若是浏览器不支持呢? 若是不支持交叉点观察者,咱们仍然能够 延迟加载 一个 polyfill 或当即加载图像。甚至还有一个 library

一般,咱们会使用懒加载来处理全部代价较大的组件,如 字体,JavaScript,轮播,视频和 iframe。 你甚至能够根据网络质量调整内容服务。网络信息 API,特别是 navigator.connection.effectiveType(Chrome 62+)使用 RTT 和下行链路值来更准确地表示链接和用户能够处理的数据。 您可使用它来彻底删除视频自动播放,背景图片或 Web 字体,以便链接速度太慢。

  1. 你是否优先加载关键的 CSS? 为确保浏览器尽快开始渲染页面,一般 会收集开始渲染页面的第一个可见部分所需的全部 CSS(称为 “关键CSS” 或 “上一层CSS”)并将其内联添加到页面的 <head> 中,从而减小往返。 因为在慢启动阶段交换包的大小有限,因此关键 CSS 的预算大约是 14 KB。

若是超出这个范围,浏览器将须要额外往返取得更多样式。 CriticalCSSCritical 能够作到这一点。 你可能须要为你使用的每一个模板执行此操做。 若是可能的话,考虑使用 Filament Group 使用的 条件内联方法

使用 HTTP/2,关键 CSS 能够存储在一个单独的 CSS 文件中,并经过 服务器推送 来传递,而不会增大 HTML 的大小。 问题在于,服务器推送是很 麻烦,由于浏览器中存在许多问题和竞争条件。 它一直不被支持,并有一些缓存问题(参见 [Hooman Beheshti介绍的文章](Hooman Beheshti's presentation) 114 页内容)。事实上,这种影响多是 负面的,会使网络缓冲区膨胀,从而阻止文档中的真实帧被传送。 并且,因为 TCP 启动缓慢,彷佛服务器推送在热链接上 更加有效

即便使用 HTTP/1,将关键 CSS 放在根目录上的单独文件中也是有 好处的,有时甚至比缓存和内联更为有效。 Chrome 请求这个页面的时候会再发送一个 HTTP 链接到根目录,从而不须要 TCP 链接来获取这个 CSS(感谢 Philip!

须要注意的一点是:和 preload 不一样的是,preload 能够触发来自任何域的预加载,而你只能从你本身的域或你所受权的域中推送资源。 一旦服务器获得来自客户端的第一个请求,就能够启动它。 服务器将资源压入 Push 缓存,并在链接终止时被删除。 可是,因为能够在多个选项卡之间重复使用 HTTP/2 链接,因此推送的资源也能够被来自其余选项卡的请求声明(感谢 Inian!)。

目前,服务器并无一个简答的方法得知被推送的资源 是否已经存在于用户的缓存中,所以每一个用户的访问都会继续推送资源。所以,您可能须要建立一个 缓存监测 HTTP/2 服务器推送机制。若是被提取,您能够尝试从缓存中获取它们,这样能够避免再次推送。

但请记住,新的 cache-digest 规范 无需手动创建这样的 “缓存感知” 的服务器,基本上在 HTTP/2 中声明的一个新的帧类型就能够表达该主机的内容。所以,它对于 CDN 也是特别有用的。

对于动态内容,当服务器须要一些时间来生成响应时,浏览器没法发出任何请求,由于它不知道页面可能引用的任何子资源。 在这种状况下,咱们能够预热链接并增长 TCP 拥塞窗口大小,以便未来的请求能够更快地完成。 并且,全部内联配置对于服务器推送都是较好的选择。事实上,Inian Parameshwaran 对 HTTP/2 Push 和 HTTP Preload 进行了比较 深刻的研究,内容很不错,其中包含了您可能须要的全部细节。服务器究竟是推送仍是不推送呢?你能够阅读一下 Colin Bendell 的 Should I Push?

底线:正如 Sam Saccone 所说preload 有利于将资产的开始下载时间更接近初始请求, 而服务器推送是一个完整的 RTT(或 更多,这取决于您的服务器反应时间 —— 若是你有一个服务器能够防止没必要要的推送。

你使用 流响应 吗?经过流,在初始导航请求中呈现的 HTML 能够充分利用浏览器的流式 HTML 解析器。

  1. 你使用流响应吗? streams 常常被遗忘和忽略,它提供了异步读取或写入数据块的接口,在任何给定的时间内,只有一部分数据可能在内存中可用。 基本上,只要第一个数据块可用,它们就容许原始请求的页面开始处理响应,并使用针对流进行优化的解析器逐步显示内容。

咱们能够从多个来源建立一个流。例如,您可让服务器构建一个壳子来自于缓存,内容来自网络的流,而不是提供一个空的 UI 外壳并让它填充它。 正如 Jeff Posnick 指出的,若是您的 web 应用程序由 CMS 提供支持的,那么服务器渲染 HTML 是经过将部分模板拼接在一块儿来呈现的,该模型将直接转换为使用流式响应,而模板逻辑将从服务器复制而不是你的服务器。Jake Archibald 的 The Year of Web Streams 文章重点介绍了如何构建它。对于性能的提高是很是明显的。

流式传输整个 HTML 响应的一个重要优势是,在初始导航请求期间呈现的 HTML 能够充分利用浏览器的流式 HTML 解析器。 在页面加载以后插入到文档中的 HTML 块(与经过 JavaScript 填充的内容同样常见)没法利用此优化。

浏览器支持程度如何呢? 详情请看这里 Chrome 52+、Firefox 5七、Safari 和 Edge 支持此 API 而且服务器已经支持全部的 现代浏览器.

  1. 你使用 Save-Data 存储数据吗? 特别是在新兴市场工做时,你可能须要考虑优化用户选择节省数据的体验。 Save-Data 客户端提示请求头 容许咱们和定制为成本和性能受限的用户定制应用程序和有效载荷。 实际上,您能够将 高 DPI 图像的请求重写为低 DPI 图像,删除网页字体和花哨的特效,关闭视频自动播放,服务器推送,甚至更改提供标记的方式。

该头部目前仅支持 Chromium,Android 版 Chrome 或 桌面设备上的 Data Saver 扩展。最后,你还可使用 service worker 和 Network Information API 来提供基于网络类型的低/高分辨率的图像。


掘金翻译计划 是一个翻译优质互联网技术文章的社区,文章来源为 掘金 上的英文分享文章。内容覆盖 AndroidiOS前端后端区块链产品设计人工智能等领域,想要查看更多优质译文请持续关注 掘金翻译计划官方微博知乎专栏

写文章能够得 异步社区 的书!爱读书的技术人都在异步社区。我想要读 《Python编程快速上手——让繁琐工做自动化》,但愿你也可以喜欢。参与写做换书活动。

相关文章
相关标签/搜索