作者: Michał Witkowski https://blog.pragmatists.com/@WitkowskiMichau
摘要: 本文从性能监控, 图片, 网络字体和 JS 代码优化以及如何提升渲染阻塞资源的加载速度等方面列举了常见的前端优化方法.
性能是决定我们 web 应用成功与否的重要因素. 一开始, 我们的 Web 应用体积较小, 几乎没有开发者会关注于持续监控用户接收的数据大小以及所需时间.
如果你不曾做过性能监控, 那么你的网站性能很可能还有提升的余地. 这时就出现了一个问题, 为了让用户能够感知到性能的提升, 你应该做出哪些努力呢?
在下面的研究中, 你可以了解到如何让用户感觉到加载时间发生了明显的变化, 并且你至少要完成 20% 的任务, 才能让用户注意到你为此付出的努力. 更多资料 https://www.smashingmagazine.com/2015/09/why-performance-matters-the-perception-of-time/#the-need-for-performance-optimization-the-20-rule
接下来的文章分为 6 个部分:
通过 Chrome Devtool Audit 检查性能
图片优化
网络字体优化
JavaScript 优化
渲染阻塞资源的加载提速
检查性能的其他程序或插件
如果你还有其他问题, 请在评论中告知. 我们的团队和读者们很乐意帮助你.
这篇文章是前端调试清单系列的一部分
性能量化
Chrome Devtools Audits
由于本系列都与 Chrome Devtools 有关, 所以这次我们从 Audit 标签开始. 它使用了 Lighthouse.
打开 Chrome Devtools, 然后选择 Audits 标签, 接着点击 Perform an audit... , 接着 Run audit .
我决定只检查 Performance 和 Best practices , 因为我不关心 Progressive Web App 或 Accessibility 的结果.
译者注: 这一步应该需要翻墙, 不然会卡在 lighthouse is warming up.
很好. 只需要等待一会儿, 我们就完成了性能检查并且把它当成衡量指标来提升网站的性能. Audits 会把网页视图更改成移动版, 对此你不需要担心有什么负面影响, 因为这是 Chrome 的默认行为. 另外, 我强烈建议你使用 Canary 版 Chrome 的 audits.Canary 版能够监控桌面端网页, 并且新增了一个节流的选项. 就像下面这张图一样.
Metrics
Metrics 下列举了基本的性能指标, 并且给出页面加载时间的概览.
First meaningful paint
-- 这代表用户看到初始内容所需的时间. 请尽量让它的值小于 1 秒. 更多资料 https://developers.google.com/web/fundamentals/performance/rail
First interactive -- 这代表可交互元素从展示到响应所需的时间.
Perceptual Speed Index
-- 这是页面展示可见部分所需时间的平均值. 它以毫秒为单位并且取决于窗口的大小. 应该尽量让它减少到 1250 毫秒以内. 更多资料 https://sites.google.com/a/webpagetest.org/docs/using-webpagetest/metrics/speed-index
Estimated Input Latency
-- 这是网页响应用户输入所需的毫秒数.
Opportunities
Opportunities -- 这一部分包含更多的性能细节, 将图片, CSS 和响应时间的信息都聚合起来了. 下面我会逐个讲解并且给出改良策略.
Reduce render-blocking stylesheets
下载 CSS 文件会阻塞浏览器的渲染过程. 也就是说, 浏览器会等到 CSS 文件下载完后才开始渲染内容. 比如说你使用了 bootstrap, 但在项目才启动的时候, 你并不需要加载整个组件库来美化你的页面. 对此, 最简单的处理方法就是只加载必要的 CSS 文件.
接着, 你希望针对不同的屏幕尺寸进行优化. 为了减少加载的 CSS 数量, 你可以使用选择性加载的方式, 只加载当前屏幕需要的 CSS 文件. 就像下面的代码:
- <link href="other.css" rel="stylesheet" media="(min-width: 40em)">
- <link href="print.css" rel="stylesheet" media="print">
如果这还没有完全解决你的问题, 你可以试试 Keith Clark 想出来的方法, 它可以让你在不阻塞页面渲染的情况下加载 CSS 文件. 这个技巧使用了一个媒体查询为无效值的 link 元素. 当媒体查询的计算结果为 false 时, 浏览器仍然会下载样式表, 但是不会延迟页面的渲染. 你可以把必需的 CSS 文件分离出来然后再下载它们. 更多资料 https://keithclark.co.uk/articles/loading-css-without-blocking-render/
Keep server response times low
减少请求数的重要性不言而喻, 但我们仍然要经常提醒自己, 不要忘记它. 为了减少服务器响应次数, 你可以考虑使用 CDN 存放部分资源文件. 还可以使用 HTTP2 协议, 删除不必要的请求或是渲染页面后再懒加载资源等等.
Properly size Images, Offscreen images 和 next-gen formats
这三个部分都属于图片优化这一类. 你可以在 Network 标签中通过筛选 IMG 来获取实际加载了哪些图片以及它们的体积大小. 现在只看 Size 和 Time 这两列的数据, 看看你是否满意这样的结果. 目前还没有普适的标准规定每个文件应该有多大, 这完全依赖于客户端设备种类, 客户群体和其他你能想到的所有因素.
关于图片优化我还想再补充几点, 因为这个问题在 Audit 的结果报告中会多次出现.
图片优化
图片分为两类: 位图和矢量图. 一个位图由像素构成, 往往被用来展示图片和复制的动画. 比如 jpg,jpeg 和 gif 格式.
矢量图由图形组成, 被用来展示 logo 和图标. 因为它们在缩放时也能有优异的表现. 比如 svg.
SVG
SVG 本身体积已经很小了, 但是你还可以通过压缩让它们更小:
- SvgOmg https://jakearchibald.github.io/svgomg/
- Svg-optimiser http://petercollingridge.appspot.com/svg-optimiser
位图
由于位图的体积较大, 所以要用的优化技巧会多一些. 下面是一些让位图保持较大尺寸但又有较小体积的黑科技.
事前准备
在优化前请先准备好不同版本的图片. 我想你不希望在普通手机上展示适用于 retina 屏幕的图片吧? 先准备个三四种版本. 手机版, 平板, 桌面版和 retina 版. 它们的尺寸取决于你的目标设备. 如果你不清楚目标设备属于这四种中的哪一个, 可以参考 这个链接 https://css-tricks.com/snippets/css/media-queries-for-standard-devices/ .
Srcset 属性
图片都准备好了吗? img 标签的 src 属性能够帮助我们决定什么时候加载图片.
<img src="ing.jpg" srcset="img.jpg, img2x.jpg 2x" alt="img">
设置 src 是防止浏览器不支持 srcset 属性, 而 srcset 是为了那些支持该属性的浏览器. img2x.jpg 是为了适配 dpr = 2 的 retina 屏幕.
<img src="img.jpg" srcset="img1024.jpg 1024w, img2048.jpg 2048w" alt="img">
设置 src 是防止浏览器不支持 srcset 属性, 而 srcset 是为了那些支持该属性的浏览器. img1024 是为了适配宽度为 1024 像素的屏幕.
上面引用的是 MDN 的 两个例子 https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images .
媒体查询
你也可以使用媒体查询, 比如说根据平板或手机使用不同的样式. 这种方法最好与 CSS 预处理配合使用.
作为 srcset 属性的替代品, 媒体查询的规则是写在 CSS 样式中, 而不是写在 HTML 文件里. 在单纯的 CSS 文件里, 这种方法往往事倍功半. 但如果你使用 CSS 预处理提供的 mixin 和变量的话, 效率就会非常高了. 当然, 是使用 srcset 还是媒体查询都随你意.
- @desktop: ~"only screen and (min-width: 960px) and (max-width: 1199px)";
- @tablet: ~"only screen and (min-width: 720px) and (max-width: 959px)";
- @media @desktop {
- footer {
- width: 940px;
- }
- }
- @media @tablet {
- footer {
- width: 768px;
- }
- }
- CDN
当准备好图片资源并且代码优化后, 你需要考虑分发的问题. 像 Cloudinary 这样的工具能够有效地降低响应延时. 它们的服务器遍布全球, 所以能够快速分发数据. HTTP 协议限制用户每次只能向一个服务器并行发送 6 个请求, 而使用 CDN 的话你能发送的请求数是它的数倍.
懒加载
有的图片色彩更饱满但体积也更大. 如果你的网站还有很高的加载延迟, 可以试试 blurry image 或是懒加载.
懒加载能够让图片按需加载. 如果一个画廊有 1000 张图片, 那么这些图片并不需要一开始就被下载好. 我们可以先加载前十张图片, 然后在用户想要查看时再加载剩下的.
关于懒加载的 第三方库 https://www.sitepoint.com/five-techniques-lazy-load-images-website-performance/ 实在是太多了.
Blurry 是现在 FaceBook 使用的技术. 当你在网速较低的情况下点开某人的个人主页, 网页中展示的图片会从模糊逐渐变得清晰. 更多资料 https://css-tricks.com/the-blur-up-technique-for-loading-background-images/
Diagnostics
Diagnostics 是检测结果的最后一项. 由于其中有一部分已经在上文中提到了, 所以我不打算再逐条讲解. 接下来, 我会笼统地讲另外一部分.
Uses inefficient cache policy on static assets
Google 喜欢缓存和 serverless 应用. 缓存策略完全由你决定, 反正我是对其兴趣不大. 如果你想了解更多关于缓存的事, Google 为你准备了一些不错的 教程 https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching#cache-control .
Critical Request Chains / render-blocking scripts
关键请求链是需要在页面渲染前完成的请求的集合. 所以最好尽可能地减少它的数量.
优化网络字体
之前我们提到过 CSS 优化, 那么现在再来聊聊网络字体的优化.
在我们的网站中, 往往会使用到 EOT,TTF,WOFF 或 WOFF2 格式的字体文件.
由于没有统一的标准格式, 所以对于每个浏览器我们都需要使用一种不同的字体文件来适配. 关于这个问题你可以看看 这篇文章 https://css-tricks.com/snippets/css/using-font-face/ . 在此之前, 你可以先问问自己是否真的需要使用网络字体. 这个答案也许可以在 这篇文章 https://css-tricks.com/snippets/css/using-font-face/ 中找到.
字体压缩
字体是图形和路径的集合, 这个集合帮助我们生成字母和文字. 幸运的是, 每一个不同的字母都有相似的地方, 所以我们可以对它们进行压缩.
由于 EOT 和 TTF 格式默认是未压缩的, 所以确保你的服务器已经开启 GZIP 配置.
WOFF 是内置了压缩功能的, 所以在你的服务器上请使用最优压缩方式.
WOFF2 则有预处理机制. 更多资料 http://www.w3.org/TR/WOFF20ER/
限制字符集
如果你的网站语言是英文, 那么没必要引入阿拉伯或希腊文. 你也可以使用 unicode 字符集, 这样可以让浏览器将大的 unicode 字体拆分成一个一个子集. 更多资料 https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/unicode-range
字体加载策略
由于浏览器在构建 DOM 时需要使用到字体, 因此加载字体文件也会阻塞页面的渲染.
合理地使用字体加载策略能够降低加载的延迟. CSS 属性 font-display 就是一种字体加载策略. 更多资料 https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display
JavaScript 优化
减少引入不必要的依赖
目前, ES6 的模块机制让 Webpack 和 Gulp 被广泛使用. 当项目中需要使用第三方库时, 切记你需要的只是整个库中的一小部分. 所以当你不需要 lodash 的全部功能时, 你可以只导入需要的函数:
import _ from 'lodash';
-- 整个 lodash 库都会被打包
import {map} from 'lodash';
-- 这也会打包整个 lodash 模块. 你可以使用 https://github.com/lodash/lodash-webpack-plugin 或 https://github.com/lodash/babel-plugin-lodash 等插件.
import map from 'lodash/map';
-- 这样只会打包 map 模块
仔细检查你使用的框架中有哪些原生方法与 ES6 方法. 有时候你并不需要针对每个功能都引入一个不同的库. 你可以使用下面链接中的工具检查 bundle 包是如何生成的.
Webpack bundle analyzer https://www.npmjs.com/package/webpack-bundle-analyzer
Bundle buddy https://github.com/samccone/bundle-buddy
其他工具
除了上文提到的 Google Devtool, 还有其他用来检查性能的工具.
http://tools.pingdom.com/ 就是其中之一, 它兼具了 Audits 与 Network 标签对应的功能.
我还向您推荐 PageSpeed Insights, 这是一个 Chrome 的插件. 它会告诉你哪些图片需要被优化.
总结
本文的目的是向你展示如何通过减少资源文件体积来轻量化你的网站. 而这仅仅是优化性能的第一步罢了. 毕竟性能优化这个方向太广了, 而且还会随着现代前端的发展而变化. 所以你需要持续关注这个领域并且保持竞争力, 始终领先他人一步.
查看更多我翻译的 Medium 文章请访问:
项目地址: https://github.com/WhiteYin/translation/tree/master
SF 专栏: https://segmentfault.com/blog/yin-translation
来源: http://www.tuicool.com/articles/nM7fUnu