2017 前端性能自查表

标签: 性能优化web development前端chrome
2099人阅读 评论(0) 收藏 举报
分类:

原文链接

下面的文字在翻译时做了些调整和补充,并不完全忠实于原文。有很多我自己也没有深入学习的点,翻译也不能保证准确,所以有时间还是看原文。阅读时需要注意区分加载性能和运行时性能的不同策略。文章涵盖很多的细节,实践中从识别出性能瓶径开始展开性能优化会更好。可以多了解下Chrome DevTools的使用。比如:
* Optimise your web development workflow视频
* Measure Resource Loading Times 打开后,左侧还有关联的几篇。
* 浏览器渲染性能优化

通常情况下需要避免微改进,虽然它能帮助不断优化性能,但它无法聚焦。我们需要使用可衡量的目标来贯穿整个开发流程。下面例出一些不同的模型,其中不乏片面的观点,但早点定义出来还是必要的。

设置目标

1.超越竞争对手20%

以前的研究表明,如果让用户感觉到性能差异,必须提高20%以上。所以我们定义性能优化的目标也不要低于这个值。页面的性能有几个不同的指标:
* 页面加载完成时间 (Full-Page loading)
* 开始渲染时间 (Start Rendering Time,使用WPT测试)
* 首次有效渲染时间 (First-meaningful paint, Chromium定义)
* 可交互时间 (Time to interactive)

首次有效渲染时间和可交互时间都可以使用Lighthouse进行测试,根据用户情况选择适当的测试环境,包括机型和网络环境。输出的样式如下:
image001
如果你愿意,也可以收集这些数据,制成表格,从中去除20%再设定出你的目标(如性能预算表(Performance budgets))。这时,如果你想通过减小JS大小来改进可交互时间,就会更加有方向了。
bugdets_opt
Performance budget builder by Brad Frost
把表格同你的伙伴分享,可以让大家都能留意到对性能的影响。

2.100ms响应时间和60fps的帧率

RAIL性能模型给出建议是:从用户操作(input)到页面做出反应(feedback)应当在100ms以内,这样页面的处理必须在50ms内完成。而对于动画这种耗时的操作,如果控制不住时间还不如什么都不做。保证用户的行为可以得到及时响应,而不是因为被页面的处理操作造成卡顿的感觉。

另外为了60fps的帧率,每帧的绘制时间应当在16ms内(最好在10ms内)完成。一些好的优化实践或者好好利用空闲时间可以做些优化。这些是运行时性能的目标,不是加载性能。

3.首次有效绘制时间低于1.25s,SpeedIndex低于1000

理想的性能目标是,在较好的网络条件下,开始渲染时间应当低于1s,首次有效渲染时间最长也要低于1250ms,SpeedIndex低于1000。在移动端,3G网络下开始渲染时间如果在3s还是可以接受的

定义环境 (DEFINING THE ENVIRONMENT)

4.选择你的开发工具

这里似乎不用特别说明,大家都有自己的见解。

5.渐进增强 (Progressive Enhancement)

在架构和发布上要保持渐进增强才能立于不败之地。先完成核心体验,再为不同的浏览器完成更为高级的功能,以此创建出弹性的用户体验(Resilient Web Design)。

6.Angular, React, Ember…

熟悉一个支持服务端渲染的框架。在选择一个框架前,最好确认下服务端渲染和客户端渲染的差异。如果发现性能问题,也很难变更所使用的框架了。对于常使用的JS框架,一定要有广泛的了解,再做好充分的评估

当创建一个Web应用时,不妨了解下PRPL模式应用框架(Application shell)架构
PRPL
PRPL代表的是:拉取关键资源,渲染首屏,资源预取,按需加载。
application-shell
一个应用框架(Application-Shell)就是最简化的HTML,CSS和JS。

7.AMP或是Instant Articles?

你或许会考虑使用Google AMP或是Facebook的Instant Articles。AMP提供了一个稳健的性能框架,而Instant Articles可以使用在Facebook上体验上更好的性能。
当然你也可以考虑下渐进式Web AMPs

8.好好选择CDN

无论什么页面,总可以其中一部分转改为静态资源(Static Site Generator),通过CDN部署,避免数据库请求。
你也可以选择基于CDN的static-hosting平台,再通过一些交互组件来增强(JAMStack)。

CDN也是可以提供动态内容的,并不需要只限定于静态内容。选择CDN时可以确认下是否会做压缩、转换、HTTP2,组装静态和动态内容等内容。

优化

9.设置优先级

先要弄清出从哪入手。可以盘点下页面中的资源(JS,图片,字体,第三方脚本和其它较重的模块,如轮播(Carousel)组件, 复杂的图文,以及多媒体资源),将它们分类列出。并区分出属于哪类需求:
* 核心体验 (Core experience)
* 增强体验 (Enhanced experience)
* 额外体验 (Extras experience, 可以进行懒加载)
可以参考这个文章中的实践进行优化。

10.使用cutting-the-mustard技术

使用cutting-the-mustard技术在老旧浏览器拥用核心体验,同时在现代浏览器上达到更好的用户体验。对应限制资源加载:
* 立即加载核心体验所需要的资源。
* 在DomContentLoaded后加载增强体验所需要的资源。
* 在load事件为额外体验加载其它资源。

注意通过浏览器版本判断设备能力的方法并不准确,而且现在也没有更好的方法。

11.考虑使用微优化(micro-optimization)和渐进式启动(progressive booting)

一些应用在可以渲染页面之前,或许需要一些时间来进行初始化。这时不要显示加载提示,那个没有任何意义。最好能显示出一个基本的样子(skeleton screens)出来。
应用一些为初始化时间提速的技术,如tree-shakingcode-splitting。还可以使用一个前置编译器通过服务端降低客户端渲染的耗时,尽快显示有意义的内容。
最后,还可以考虑使用Optimize.js来实现快速初始化(但可能不再需要了)。
progressive-booting
渐进式启动(Progressive booting)就是先通过服务器端渲染快速完成首次有效渲染,再通过最小的JS让可交互时间接近于首次有效渲染时间。

客户端渲染还是服务器端渲染呢?通过渐进式启动(Progressive booting)就是先通过服务器端渲染快速完成首次有效渲染,再通过最小的JS让可交互时间接近于首次有效渲染时间。然后根据需要加载其它内容。不幸的是,Paul Lewis却指出这个实践很难通过现有的框架实现。但你仍然可以考虑用它完成启动速度的极致优化。

12.HTTP cache的响应头有没有设定好

这一点很容易被忽略。一定要确认expires, cache-control, max-age等这些http cache相应的响应头都设定正确了。

可能的话,就为静态资源使用cache-control: immutable,避免不必要的验证(目前还只有Firefox针对https页面支持)。详细的内容,可以参考:
Heroku的Primer on HTTP caching headers, Jake Archibald的Caching Best Practices, 以及Ilya Grigorik的HTTP caching primer

13.限制第三方库的使用,异步加载JS

因为浏览器渲染页面的流程,JS资源会阻塞渲染流程。对于一些不会影响首屏渲染的JS可以使用deferasync属性。
在实践中,如果需要考虑IE9之前用户,建议使用async。另外要限制第三方库和脚本的使用,特别是分享按钮和<iframe>中引用的。可以使用静态分享按钮(比如SSBG)和静态链接(static links to interactive maps)的方式来解决。

14.优化图片

尽量使用响应式图片<picture>元素。还可以利用<picutre>加上JPEG回退处理来使用WebP格式的图片。对于UC浏览器也可以使用H.264格式图片。Sketch直接支持WebP, 也可以在Photoshop中使用插件导出,或者其它方案
responsive-image
Responsive Image Breakpoints Generator可以自动处理图片,并生成标签。

也可以尝试使用client hints,增加更多的设备信息,让服务器返回不同的图片请求。需要注意它对CDN的影响。工具Responsive Image Breakpoints Generator或者Cloudinary也可以帮助简化你的工作。大部分情况下,单独使用srcsetsizes也能有很不错的效果。
另外在Smashing Magazine, 在图片命名时使用-opt后缀,如brotli-compression-opt.png,所有人都会知道这个图片已经被优化了。

15.进一步优化图片

如果页面需要快速的加载图片,可以:
* 使用Progressive JPEG,并且使用mozJPEG压缩一下,它能够通过处理扫描层次来改善启始渲染时间。
* 使用Pingo处理PNG图片。
* 使用Lossy GIF处理GIF图片。
* 使用SVGOMG处理SVG图片。
去掉图片一些不必要的部节,比如缩略图,EXIF信息,或者应用高斯模糊过滤下,这样可以降低图片大小 (那些数据有时比你想像的要大很多!)。必要时可以降色,甚至是使用黑白图片。对于背景图,在导出图片时以0~10%之间的品质输出也是可以的。

可以参考了解更多的内容:
* Improving Perceived Performance with Multiple Background Images
* How Medium does progressive image loading
* Tiny Thumbnails
* The “Blur Up” Technique for Loading Background Images

16.优化字体文件了吗?

这个主题并不太适用于中文环境,可以做个了解。如果使用中文字体,需要特别慎重,它们的字体文件都是以MB为单位的。
概括一下要点:
* 使用WOFF2。
* 参考Comprehensive Guide to Font-Loading Strategies并且使用Serivce Worker - Cache来缓存字体。
* 要快速有效,可以参考Pixel Ambacht的方法
* 如果依赖于第三方提供的字体,可以使用Web Font LoaderFOUT会优于FOIT
* 异步的字体加载可以使用loadCSS
* 使用系统字体代替
* 网页字体优化
再给一个中文字体的参考:
* Web 字体的选择和运用

17.及早推送关键的CSS

把首屏需要的样式,即关键的CSS(Critical CSS), inline到页面里已经是常用的实践,但本质上它只适用于首次加载显示的场景(Why inlining everything is not answer!)。在移动网络下,要综合主文档的大小来决定内联CSS的策略,因为内联CSS增大了主文档反而可能会使得主文档的首次有效渲染的耗时变长,特别是忽略了浏览器本身的Memory Cache和Http Cache的作用。(所以对于任何教条式的规则一定要区分它所针对的场景!!)

综合考虑加载的耗时,关键CSS的大小最好保持在14KB,注意这是PC上的数据!如果是移动网络,不要让主文档太大,总之越小越好。有两个工具可以帮助完成:CriticalCSSCritical
也可以使用Filament Group的conditional inlining approach

如果使用HTTP/2,关键CSS可以存在多个CSS文件,通过服务器推送到达客户端,不过可能遇到一些缓存上的坑,参考Hooman Beheshti幻灯片中第 114页。但是服务器推送还是比保持连接更为有效,可以考虑创建一个可感知缓存状态的服务器推送机制。已经有一个新的cache-digest规范尝试从标准层解决这个问题了。

18.使用Tree-shaking和Code-splitting减少加载的流量

Tree-shaking能够帮你清理掉生产环境中不需要的代码,也可以使用Webpack 2去掉不需的模块输出。使用UnCSS或者Helium清除掉不再使用的CSS。另外,你可能还会考虑下如何写出更有效的CSS选择器,以及如何避免引入复杂的样式

Webpack的另一个特性, Code-Splitting, 可以将代码分段以便按需加载。它可以帮助你做到减少初次下载,其余代码则按需加载。

还是 Rollup比Browserify的导出有更好的表现。使用Rollupify还可以将ECMAScript 2015转成一个大的CommonJS模块,因为小的模块会有更大的性能开销

19.改进渲染性能

将渲染开销较大的组件使用CSS containment隔离开来,比如限定样式的作用域,或者第三方插件(widget)等。确保在动画或者滑屏时不会有卡顿。如果实在做不到,可以让页面交错达到60~15的帧率。使用will-change来通知浏览器哪些元素的哪些属性会发生变化。

另外,最好还是通过Chrome DevTools来全面的评估渲染性能。可以从Paul Lewis的免费课程开始。另一个不错的文章是Sergey Chikuyonok的GPU Animation: Doing It Right

20.预热网络连接

使用Skeleton screens(先显示基本的框架),并且对开销大的元素执行懒加载,如字体、JS、轮播元素、视频和iframe。也可以使用Resource Hints中定义的一套预处理策略。
* dns-prefetch DNS预解析
* preconnect 预连接
* prefetch 预加载且会运行(JS)
* preload 预加载,但不会运行
* prerender 预渲染,成本太高不建议使用
实践中并不是需要这些特性混合使用,比如通常preconnect会比dns-prefetch更有效。preload则会比prefetchprerender有更高的收益(更易于使用)。

翻译就到这里了,剩余的部分主要和HTTP/2有关,里面还是有些关键内容的,简单概述如下:
* 有没有使用Brotli或者Zopfli压缩?
* 有没有使用OCSP简化TLS握手?
* 有没有使用HPACK精简响应头?
* 有没有使用Service Worker进行更精细的控制?

2
0

猜你在找
【直播】机器学习&深度学习系统实战(唐宇迪)
【直播】Kaggle 神器:XGBoost 从基础到实战(冒教授)
【直播回放】深度学习基础与TensorFlow实践(王琛)
【直播】计算机视觉原理及实战(屈教授)
【直播】机器学习之凸优化(马博士)
【直播】机器学习之矩阵(黄博士)
【直播】机器学习之概率与统计推断(冒教授)
【直播】机器学习之数学基础
【直播】TensorFlow实战进阶(智亮)
【直播】深度学习30天系统实训(唐宇迪)
查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:1476782次
    • 积分:16392
    • 等级:
    • 排名:第605名
    • 原创:221篇
    • 转载:30篇
    • 译文:47篇
    • 评论:361条
    微博/MSN/EMail

    新浪微博:Horky
    QQ:324014340
    Mail:horky.chen@gmail.com
    微信公众号 (聚焦软件开发):
    博客专栏
    最新评论