前端业务开发-性能优化

什么是性能?前端业务开发关注的性能,主要有两个:加载速度、渲染效率。二者一般也合称【性能体验】。

加载速度

衡量加载速度的传统指标一般是:首字节、DOMContentLoaded、onLoad。传统指标的问题是,完全站在技术视角衡量,并不能代表用户实际的体验。目前受业界广泛认可的是谷歌提出的一套面向用户的指标 Progressive Web Metrics

  • FP(First Paint)白屏结束,有可见像素出现了
  • FCP(First Contentful Paint)对用户有意义的内容出现了
  • FMP(First Meaningful Paint)同上
  • TTI(Time to Interactive)js 执行完了,可以交互了

FP 定义了【白屏时间】,后面两个定义【首屏时间】。从技术角度看怎么知道什么是 Contentful,什么是 Meaningful?基本策略是检测 DOM 节点变化最大的时刻,不过最精确的还是得靠自定义埋点,毕竟这个指标归根结底是用于帮助开发掌握页面在线上运行的实际状况,也只有开发最清楚页面内容的加载过程。TTI 最好也用自定义埋点,靠技术手段检测会 比较麻烦

在实践中,我们需要在 关键路径 上的各个节点添加监控埋点,从 url 发出请求,到 DNS 解析,到服务端处理(如果是服务端渲染的话),到 html 开始加载,到阻塞类资源加载,到业务代码开始执行,到接口返回,到内容正式渲染。这样才有利于分析究竟是哪个环节影响了最终性能。


张克军的这张图描绘了网页通用的加载模型,在实际业务中通常还存在其他一些环节。比如移动端 hybrid 页面或 RN 页面的容器初始化过程,比如前置校验用户登录态、获取用户定位等等。

上述指标只是衡量了单个页面的性能,看不到产品整体的性能,因此大厂基本都在搞一个叫【秒开率】的指标。秒开率是指整个样本集中,某指标小于 1s 的占比。秒开率回答了这样一个问题:整个产品有多少页面的性能指标(一般取 90 分位线)小于 1s。

渲染效率

渲染效率就是指页面流畅度,看交互动效是否有卡顿(掉帧)。衡量渲染效率的指标主要是 FPS。查看 FPS 最简单的办法有两个,一是用 stats.js ,二是在 chrome devtools 中通过 command + shift + p 调出命令窗口,输入 fps 即可调出帧率面板。
由于 UI 线程和 js 线程共用同一个线程,js 任务的运行可能导致 UI 卡顿、卡死,因此浏览器还提供了一个用于监控 long task 的 api。

参考: 百度APP流畅度全流程质量监控实践(一) 流畅度现状分析

监控

通常我们发现某个页面性能已经很差了,于是一顿专项优化,最后各项指标都达到了预设目标,但问题是怎么保证性能长期不会继续劣化呢?为了知道页面在线上运行的实际性能状况,首先就得把监控体系建立起来,能对采集到的指标数据做各种聚合展示以便随时看到页面指标数据变化,能定期自动生成报表,能对指标异常变化(比如突增、骤降)添加报警。

为了采集性能数据,浏览器提供了一系列专门用于监控性能的 API,例如 navigation-timingresource-timinguser-timing 等。通用指标可封装 sdk 进行采集上报,sdk 应该同时提供上报自定义测速点的能力。

除了线上监控,性能保障还有赖于事前防控。比如在上线流程,应该有一道性能检测环节(checklist),防止一些明显的、常见的、比较极端的性能劣化场景,比如上了一个特别大的资源而不自知(不小心全量引入了 lodash、加了张没压缩的大图、引入了无用的资源等)。最简单的思路,就是上传到 ligthouse,如果检测得分低于阈值,就直接禁止上线。这种检测既可以在上线前执行,也可以定期循环执行。

性能分析

通常监控已经能提供比较详细的性能状况数据,不过排查问题时通常还需要一些工具辅助以获得更加细节的信息。

浏览器提供了一系列衡量性能的工具,可查看 资源加载时序分析网页性能分析代码执行耗时分析渲染流畅度 等。

现代框架一般也提供了运行时的性能分析工具。比如 react profiler ,可方便的看到组件级乃至方法级的执行耗时(针对【渲染效率】)。


其他分析工具

加载性能优化

性能优化的基本思路,是搞清楚整个加载链路出问题的环节,然后针对性的修复。具体的手段,主要有四种类型:

  • 体量规划
  • 时序规划
  • 距离规划
  • 定向优化

其实还有一种严格说只能算体验优化的手段,就是从交互上让用户感觉得快,比如骨架屏,还有图片的渐进式加载(可参考 how medium does progressive image loading )。

体量规划

通常来说,加载资源的总量越小,加载性能越好。针对 web 而言,主要是限制请求资源的体积。单从资源体积的角度看,理想情况是完全的按需加载,即每时每刻仅加载当前需要的资源。

  • 只请求当前环境需要的资源
  • 减小资源体积(雅虎14条之4、10)
    • uglify
    • Gzip(服务端开启,只压缩文本文件,不要压缩图片这类的二进制文件, 原因
    • 图片优化(压缩、像移动端一样针对屏幕尺寸和分辨率加载不同大小/质量的图片、根据网络状况加载不同质量的图片、用 webp 格式)
    • 控制 cookie 大小
    • 控制 header 大小
    • 用字符数最少的代码:例如用 void 0 代替 undefined
  • 减小无效资源(雅虎14条之4、12)

时序规划

小学奥数里有个主题叫统筹规划,其中有一类问题就是看如何安排各种事情的执行流,以最小化总时间。时序规划也是类似,最基本的两种思路,就是并发和前置,要么一起搞,要么提前搞。

  • 并行
  • 前置
    • SSR:将模板渲染前置到服务端处理
    • prefetch、prerender、preload
    • 容器预初始化
    • 管道:无需等所有数据加载完才处理,而是加载一部分就处理一部分(html 的渲染就是这样的)

距离规划

距离规划的基本原理是:传输速度有上限,因此距离越近,时间越短。距离最近的是寄存器/内存,最远的是服务器。

  • CDN (雅虎14条之2)
  • 缓存
    • http 缓存(雅虎14条之3、13)
    • 使用可缓存的 get 请求(雅虎14条之14)
    • 服务器缓存
    • localStorage
    • web worker
  • kv-storage
  • stale-while-revalidate
  • 避免重定向(雅虎14条之11)
  • 服务端推送(单向传输,避免一来一回)

通常能够被缓存并且缓存能起到较大作用的,是不常变化、会被反复用到的静态信息。经常变化的信息,或者很少重复使用的信息,会影响缓存的命中率。要利用缓存,在设计上就需要考虑 动静分离 ,比如与用户状态无关的配置信息和与用户状态相关的动态信息分开使用不同接口。

为了让经常变化的数据也能使用缓存来提高效率,也有一种思路:每次都先从缓存里取数据,然后每次都发送请求更新缓存,以时间换空间,以 1 次延迟的代价,来提高接口请求的性能。这种策略还有个专门的规范叫 stale-while-revalidate ,基于 react hook 实现的网络请求方法库 swr 已经内置了该策略。

定向优化

前三种思路属于通用思路,比如 CPU 的性能优化也会采用这些思路。而定向优化是指针对环境的特征,提供专门的优化方案。就 Web 而言,特定环境主要是指:浏览器的请求、加载和渲染机制;http 协议;js 引擎。

针对浏览器机制

针对 http 1.1

  • 减少请求次数(雅虎14条之1)
    • 合并资源(bundle / spites)或合并资源的请求(CDN Combo)
    • 合并多个 ajax 请求
    • CSS inline
    • 使用 CSS、SVG、Inline Image、Icon-font 代替图片
    • 避免使用 @import 和 iframes
    • 控制域名数量,减少 DNS 查询(雅虎14条之9)
  • 选择更先进的协议:UDP、QUIC、SPDY、http 2
  • 《Web 性能权威指南》

针对 js 引擎

  • 使用更高效的 api
    • jsperf.com/
    • 编写有利于引擎优化的代码。比如按照 asm.js 规范编写的代码,将直接获得引擎层面的优化支持
    • 《High Performance Javascript》

优化手段有很多,但收益并不相同,像针对 js 引擎的优化,基本只有框架会去做。有明显收益的,主要是缓存、按需加载、减小资源体积、请求并发/前置,可参考淘宝天猫首页性能对赌优化回忆录(链接: pan.baidu.com/s/1mgILtDfD… 提取码: impp),可以说是把这些手段用到了极致。

有想了解更多的小伙伴可以加Q群链接里面看一下,希望能够对你们有所帮助。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269