众所周知,性能十分重要。然而,咱们真的知道性能瓶颈具体在哪儿吗?是执行复杂的 JavaScript,下载缓慢的 Web 字体,巨大的图片,仍是卡顿的渲染?研究摇树(Tree Shaking),做用域提高(Scope Hoisting),或是各类各样的与 IntersectionObserver、Clients Hints、CSS containment、HTTP/2 和 Service Worker 一同工做的华丽的加载模式真的有价值吗?最重要的是,咱们从哪里开始优化性能,以及咱们如何创建长期的性能文化呢?前端
之前,性能每每只是过后的想法。一般直到项目最后的时候才会被考虑,而后被归结为压缩、合并、静态资源优化或者对服务器配置文件的一些细微调整。如今回想起来,事情彷佛已经发生了很大的变化。数据库
性能不只仅是一个技术问题:它很重要,并且当把它引入到工做流时,设计决策必须根据其性能影响来决定。咱们必须不断的测量、监视和改进性能,并且 Web 日益复杂的状况带来了新的挑战,使得性能指标难以被跟踪,由于性能指标将因设备、浏览器、协议、网络类型和延迟(CDN、运营商、缓存、代理、防火墙、负载平衡器和服务器都在其中发挥做用)而有很大差别。浏览器
所以,若是咱们创做一个在提升性能时必须牢记的全部事项的概述——从流程的一开始到网站的最终发布——这样的列表将是什么样子?下面就是 2018 前端性能检查表(希望不偏不倚和足够客观)——说明您可能须要考虑的问题,以确保您的站点响应时间快、用户交互流畅,而且不会用尽用户的带宽。缓存
下面是您可能须要考虑的前端性能问题的概述,以确保您的响应时间快速而流畅。安全
(译注:原文详细地阐述了文中所涉及的全部优化策略的原理和前因后果。此处仅翻译了原文中附带的 PDF 检查表文件,意在提供一个快速、简洁的性能优化清单。)性能优化
1、准备:规划和指标服务器
只要团队之间没有协做,高性能就没法长期维持。研究用户反馈中常见的抱怨,看看提升性能是否能够帮助缓解其中一些问题。用真实数据来创建适合本身的案例和模型。在设计过程当中就开始规划加载顺序和权衡。babel
并不是每一个指标都同等重要。研究最重要的度量标准:通常而言,它与您开始渲染最重要像素的速度以及提供输入响应的速度有关。根据客户的感觉肯定页面加载的优先级。可交互时间、页面大标题元素的渲染时间、首次有效绘制时间(FMP)、速度指数(Speed Index)通常都很重要。网络
收集表明您受众的设备上的数据。在数据来源上,真实设备比模拟数据更好。选择一台 Moto G四、中端三星设备或者 Nexus 5X 等性能良好的中端设备。或者,也能够经过在电脑上,经过设置网络限速(例如:150ms RTT,1.5Mbps 下载,0.7Mbps 上传)和 CPU 限速(5 倍慢速)以模拟移动体验。最后在常规 3G、4G 和 Wi-Fi 之间切换。收集数据、设置电子表格、将指标提升 20% 并设置目标(即,“性能预算”)。框架
确保团队中的每一个成员都熟悉该清单。每个决策都涉及性能问题,前端开发人员的积极参与将使您的项目受益不浅。将你的性能预算映射到设计决策上。
2、制定现实的目标
每帧动画应在少于 16 毫秒(理想状况下为 10 毫秒)内完成,从而达到每秒 60 帧(1 秒 ÷ 60 = 16.6毫秒)。保持乐观,明智地利用空闲时间。对于像动画这样的高压点,只要能,就不要作任何其它事情。预计输入延迟时间(Estimated Input Latency)应低于 50 毫秒。
目标是在 1 秒内(在高速网络下)完成首次绘制(FMP),速度指数(SpeedIndex)低于 1250 毫秒。考虑速度基线是一台有着 3G 网络的,价格为 200 美圆左右的 Android 手机(译注:国产千元机水平),那么能够以 400 毫秒 RTT 和 400kb/s 的传输速度进行网络模拟,以达成可交互时间(Time-To-Interactive)小于 5 秒,第二次打开的速度低于 2 秒。尽你所能地下降这些指标。
HTML 的前 14~15kb 是最关键的核心块(chunk),也是整个文件中惟一能够在第一个 RTT 内被下载的部分。要实现上述目标,请设定关键文件的最大尺寸“预算”。170kb gzip 后的文件(原始文件尺寸 0.8~1mb),在普通手机上可能须要 1 秒才能解析和编译完成。
3、定义环境
不要太注意所谓的“酷”。只要您可以快速得到结果,并且在维护构建过程上没有问题就很好了。
首先设计和构建核心功能,而后再在此基础上为功能强大的浏览器的高级功能加强效果,从而建立弹性的体验。若是您的网站在性能差、网络差的机器上还能运行得比较快,那在性能好、网络棒的机器上只会运行得更快。
用 JavaScript 实现交互效果的成本至关高昂。170kb 的尺寸预算已经包含了核心的 HTML / CSS / JavaScript、路由、状态管理、工具函数、框架还有产品逻辑,所以,请完全检查咱们选择的框架的网络传输成本、解析 / 编译时间和其运行时的时间成本。
并非每一个项目都须要框架。可是若是你的项目须要框架,那么最好选择使用一个支持服务器端渲染(SSR)的框架。在使用框架以前,请确保在移动设备上以服务器端渲染和客户端渲染两种模式来评估框架的启动时间。了解您将依赖的框架的具体细节。了解 PRPL 模式和 App Shell 模型。
(译注:AMP 为 Google 的开源项目,意在以组件化的形式以提高移动设备对网站的访问速度;Instant Articles 是 Facebook 的协议,意在经过渲染页面的精简版本以提高页面在 Facebook App 内的打开速度。在国内,MIP 是和 AMP 相似的解决方案。)
没有它们,你也能够得到良好的性能。可是 AMP 提供了一个可靠的性能框架,有免费的 CDN ,而 Instant Articles 将提升你在 Facebook 上的知名度和性能。你也能够构建一个渐进式 AMP(译注:Progressive Web AMP,PWA 和 AMP 的结合体)。
您能够将部份内容“外包”给静态站点生成器,而后将其推送到 CDN,并从CDN 提供静态版本,从而避免数据库请求(即 JAMStack)。固然,这取决于您拥有的动态数据量。仔细检查 CDN 是否为您执行了内容压缩和转换、智能 HTTP/2 和边缘端包含(ESI, edge-side includes)。
4、优化构建
把你全部的静态资源(JavaScript,图片,字体,第三方脚本,尺寸大的模块)列成一个表,而后把它们按优先级分红三组:基本核心功能(老浏览器也能浏览的核心内容)、加强体验效果(为现代浏览器设计的强大功能和丰富体验)、附加功能(不必定须要而且能够惰性加载的资源,好比字体、轮播脚本、视频播放器、分享按钮等)。
(译注:“符合标准”技术(cutting-the-mustard technique)是 BBC News 开发者博客提出的,一种基于浏览器特性来检测其支持程度,并以此选择要加载哪些功能的技术。)
对老旧的浏览器,仅输出核心功能代码;对现代浏览器输出加强的功能代码。严格按标准加载静态资源:直接加载核心代码,在 DOMContentLoaded 事件中加载加强代码,并在 load 事件中加载剩下的代码。注意:廉价的 Android 手机虽然很符合标准,但这些手机的内存和 CPU 性能有限。所以,您可能须要使用读取设备内存大小的 JavaScript API 来检测设备性能,只有不支持的时候才按“符合标准”技术来。
因为解析 JavaScript 很耗时,因此请尽量的减小 JavaScript 的体积。在构建 SPA 时,您可能须要用必定时间初始化应用程序以后,才能开始渲染页面。寻找能够加快初始渲染事件的模块和技术(在低端移动设备上,这能够轻松将速度提升 2-5 倍)。完全检查每个 JavaScript 依赖,以找出谁在消耗初始化的宝贵时间。
使用服务器端渲染来得到快速的首次有效绘制时间(FMP),但也在页面里输出一些最小功能的 JavaScript 来保持交互时间(TTI)接近首次有效绘制时间(FMP)。而后,若是有须要或者有多余的时间,才开始启动应用程序的非必要部分。在加载时显示一个骨架屏幕,而不是“加载中”动画。
使用摇树(Tree Shaking)技术和代码分割(Code Splitting)技术以减小代码体积。
摇树(Tree Shaking)技术是一种经过丢弃未使用的代码以在构建过程清理代码的方法。代码分割(Code Splitting)技术将您的代码拆分为按需加载的“chunks(块)”。做用域提高(Scope Hoisting)技术使得链式的依赖能被无缝地转换成行内函数。经过 WebPack 将上述技术用于您的代码。使用 AOT 编译器(译注:例如 Closure Compiler)将一些客户端计算移到服务端。
做为开发者,咱们必须显式地使用 defer
和 async
属性来告诉浏览器不要等待脚本下载、开始渲染页面。若是你不须要关注 IE 9 及如下版本的浏览器,那么使用 defer
更好;不然,使用 async
更好。使用静态的分享按钮、静态连接交互式地图而不是使用第三方库。
从新检查你是否正确的设置了 Expires, Cache-Control, Max-Age 等 HTTP 缓存控制响应头。一般而言,一个资源要么只被缓存很短的时间(好比常常修改的资源),要么永久缓存(好比不会被更改的那种资源)。使用专为带哈希指纹的静态文件设计的响应头 Cache-Control: imuutable
以免浏览器从新请求文件。
5、静态资源优化
Brotli 是一种新的无损压缩格式。如今,全部的现代浏览器都支持它。它比 Gzip 和 Deflate 压缩率更高,压缩很是慢,可是解压速度很快。使用最高压缩比的 Brotli+Gzip 预压缩静态文件,并使用 1~4 级的 Brotli 实时压缩动态内容。也顺便检查一下 CDN 是否支持 Brotli。或者,你也能够试试在不常变化的资源上使用 Zopfli —— 它将数据用 Deflate、Gzip 和 Zlib 格式压缩,而且被设计为一次压缩、屡次下载。
尽量使用经过 srcset
、sizes
和 <picture>
元素实现的响应式图片。使用 WebP 格式的图片;这可经过 <picutre>
标签配合 JPEG fallback,或者经过 Accept
请求头来实现。对于核心图片,使用渐进式的 JPEG 并用高斯滤镜模糊掉不重要的部分。
您使用的 Web Font 极可能包含未真正被使用的执行和额外的特性。制做字体的子集(译注:仅包含部分文字的字体,如 fontmin 等方案)。优先使用 WOFF2 并使用 WOFF 做为后备。当即使用后备字体显示文字、异步加载字体(例如,使用 loadCSS),而后再切换字体。同时也考虑本地操做系统中已经安装了的字体。不要忘记在 CSS 中写 font-display: optional
;若是你没法从您的服务器加载字体,请记得使用 Font Load Events。
6、分发优化
将全部首屏渲染所须要的 CSS 放在一块儿,而后方法在 <head>
标签中。考虑有选择的内联的方法。或者,使用 HTTP/2 服务端推送;但这样你可能须要构建一个可感知缓存的 HTTP/2 服务端推送机制。
因为 ES2015 已被普遍支持了,您能够考虑使用 babel-preset-env
以仅转译现代浏览器不支持的 ES2015+ 特性。而后你能够编译两份,一份是 ES6 ,另外一份是 ES5。使用 <script type="module">
使得有 ESM 支持的浏览器加载新文件,剩下的老的浏览器可使用 <script nomodule>
来加载老的文件。
使用 CSS 包含(CSS Containment)隔离渲染十分耗时的组件。请保证在滑动页面或者元素动画的时候,页面不会卡顿,并且你的页面能持续以 60fps 的速度渲染。若是那不可能,那么至少也要把 fps 控制在 15~60 之间。使用 CSS 的 will-change
属性通知浏览器哪一个元素将会变化。
Intersection Observer API 提供了异步监听目标元素与祖先元素或顶层文档视口交点中的更改的能力。浏览器支持?Chrome, Firefox, Edge 和三星浏览器都支持了。WebKit 还在开发。浏览器不支持?懒加载一个 polyfill。
不要低估感知性能的做用。在加载静态文件时,尽可能始终领先用户一步,这样在后台发生不少事情时,会感受体验上很快。例如,要让用户持续关注你的页面,请使用骨架屏幕而不是一些加载中的动画。
使用骨架屏幕,而后懒加载全部的大型组件,好比字体、JavaScript、轮播图、视频和 iframe 等。使用资源提示(Resource Hints),如 dns-prefetch
、preconnect
、prefetch
和 preload
来节省时间。
7、HTTP/2
HTTP/2 支持很好,并且提供了不小的性能提高。缺点是,您必须迁移到 HTTPS;根据您不支持 HTTP/2 的用户群大小,你可能须要为 HTTP/1.1 和 HTTP/2 的用户返回不一样版本的代码,这就要求您调整您的编译工具。
您须要在打包模块和并行加载许多小模块之间找到一个良好的平衡。将整个界面分解为许多小模块;而后分组、压缩和打包。整个网站分为大约 6 到 10 个包应该是一个不错的折衷方案(对于传统浏览器来讲也不错)。经过实验和数据监测来为您的网站找到正确的平衡。
Save-Data 请求提示头可让咱们为关心流量费用和性能的用户提供个性化的响应。例如,你能够把全部高清的图片都改为低清的,不用 Web Font 和华丽的动效,关掉视频自动播放和服务器推送,甚至修改你的应用界面。
再次检查安全标头是否设置正确,消除已知漏洞,并检查 SSL 证书。确保全部外部插件和跟踪脚本都是经过 HTTPS 加载的、没有 XSS,而且 HSTS 响应头和内容安全策略(CSP)响应头都已正确设置。
不一样的服务器和 CDN 可能对 HTTP/2 有不一样的支持。使用 Is TLS Fast Yet? 来检查你的设置,或者直接看看你的服务器性能如何,支持的特性状况怎么样。
在服务器上启用 OCSP Stapling 有助于提高 TLS 握手速度。OCSP 协议可让浏览器无需下载并检索证书信息,从而减小握手时间。
研究标明,IPv6 的邻居发现(NDP)和路由优化可使网站快 10% ~ 15%。升级到支持 IPv6 的 DNS 觉得将来作好准备。只需确保双栈网络能正常工做——这使得 IPv6 和 IPv4 能同时运行。毕竟,IPv6 不是向后兼容的。
若是你使用了 HTTP/2,再次检查你的服务器是否实现了 HPACK 压缩。HPACK 压缩能够压缩 HTTP 响应头,以减小没必要要的开支。因为 HTTP/2 服务器如今都很新,他们可能不能彻底支持包括 HPACK 压缩在内的全部标准。H2spec 是一个很是好的用于检测标准支持程度的工具。
网络再怎么优化,也不会比本地缓存更快。若是你的网站使用了 HTTPS,那么你能够把静态资源放在 Service Worker 的缓存中,而不用请求网络。
8、测试和监控
若是您最近从 HTTP 迁移到了 HTTPS,请确保使用相似 Report-URI.io 之类的服务监控了严格的或被动的混合内容报警。你也能够用 Mixed Content Scan 来扫描你的 HTTPS 站点上是否有非 HTTPS 的混合内容。
选择一个调试工具,并试着点击每个按钮。请确保您理解如何分析渲染性能、控制台输出、调试 JavaScript 和编辑 CSS 样式。
在 Chrome 和 Firefox 上测试是不够的。请看看你的网站在代理浏览器和老式浏览器(包括 UC 浏览器和 Opera Mini 等。译者注:此处的代理浏览器即指国内浏览器中常见的云加速功能)上是什么样子。统计你受众国家的网络平均速度,避免出现重大意外。使用网络节流并模拟高 DPI 设备。虽然 BrowserStack 很好,但也得在真机上测试。
良好的性能指标是被动和主动监控工具的组合。拥有 WebPagetest 的私有实例和使用 Lighthouse 确实有利于快速测试,但也须要使用诸如 Calibre、speedscurve 等 RUM 工具创建持续的监控体系。设置您本身的用户计时打点以监控特定的业务速度指标。
9、速战速决
此列表至关全面,完成全部优化可能须要至关长的时间。若是你只有一个小时的时间,但又想得到显著的提高,你应该怎么作?咱们挑出了 10 个最容易实现的方法。显然,在开始以前和完成以后,请统计结果,包括 3G 和有线链接上的开始渲染时间和速度指数(SpeedIndex)。
统计真实的用户体验,设置可接受的目标。一个好的目标大体是:FMP < 1s,速度指数 < 1250,TTI 在 3G 网络上 < 5s 、二次访问 < 2s。优化开始渲染时间和 TTI。
为你的主模板准备核心 CSS,并放在 <head>
标签里(你的预算是 14KB)。对于 CSS/JS,请保证核心文件尺寸最大为 170kb (gzip 后的尺寸;压缩前 0.8~1Mb)
延迟或懒加载尽量多的脚本,无论是你本身的仍是第三方的——特别是分享按钮、视频播放器和其它的复杂模块。
增长资源提示,包括 dns-lookup
, preconnect
, prefetch
和 preload
。
为 Web Font 建立子集,并异步加载(或者干脆别用)。
优化图片。考虑在关键的页面(好比落地页)上用 WebP 格式。
检查 HTTP 缓存头和安全头是否正确设置了。
在服务器上启用 Brotli 或者 Zopfli 压缩。若是不支持,别忘了开 gzip。
若是有 HTTP/2,启用 HPACK 压缩并上报混合内容警告。若是使用了 LTS,那么请打开 OCSP 装订。
若是可能,将静态资源(包括字体、样式、脚本和图片等)尽量多地在 service worker 里缓存起来。
Huge thanks to Yoav Weiss, Addy Osmani, Artem Denysov, Denys Mishunov, Ilya Pukhalski, Jeremy Wagner, Colin Bendell, Mark Zeman, Patrick Meenan, Leonardo Losoviz, Guy Podjarny, Andy Davies, Rachel Andrew, Anselm Hannemann, Patrick Hamann, Andy Davies, Tim Kadlec, Rey Bango, Matthias Ott, Mariana Peralta, Philipp Tellis, Ryan Townsend, Mohamed Hussain S H, Jacob Groß, Tim Swalling, Bob Visser, Kev Adamson and Rodney Rehm for reviewing this article, as well as our fantastic community, which has shared techniques and lessons learned from its work in performance optimization for everybody to use. You are truly smashing!
推荐阅读
(点击图片便可跳转)
Brilliant Open Web
BOW(Brilliant Open Web)团队,是一个专门的Web技术建设小组,致力于推进 Open Web 技术的发展,让Web从新成为开发者的首选。
BOW 关注前端,关注Web;剖析技术、分享实践;谈谈学习,也聊聊管理。
关注 OpenWeb开发者,回复“加群”,让咱们一块儿推进 OpenWeb技术的发展!