近年移动业务喷井式爆发,伴随着互联网人口红利的萎缩,用户更加青睐效率高体验优的站点,页面「到达」快慢直接影响了用户的体验,「性能」变得愈来愈重要。google 大数据统计观察发现,移动端用户对页面加载慢的容忍度远低于 PC 端,投放页面首屏加载时间从 2s 钟延迟到 3s 会形成 9.4% 的 PV 降低,8.3% 的跳出率增长以及 3.5% 的转化率降低。性能优化具备的商业价值不言而喻,总不能眼看着市场同事辛苦「求」来的用户在咱们手中流失吧?这是身为一个合格前 yíng 台 bīn 不能容许的!盘他!html
有些公司同时想到的第一件事就是「优化」,网上搜一波性能优化的列表,把别人的「最佳实践」照搞一番,性能确实会有提高,但效率未必是最高的,反倒有些本末倒置,别人的问题未必就是本身的问题,「并行不表明因果」,要作性能优化,首先要作的是掌握详尽的性能指标信息,根据木桶原理,找到最拖后腿的指标「短板」,重点优化,将边际成本最小化。因此,首先咱们要作的应该是性能指标的收集分析。前端
指标收集主要分有三种方式:git
以 Google 的 Lighthouse 最为著名,它是一个开源的自动化工具,能够安装为 Chrome 的扩展插件,也能够命令行直接运行,它将针对目标页面运行一连串的测试,而后输出一个有关页面性能的评分报告。github
根据此报告,能够有的放矢,逐一优化。web
优势:算法
1. 评分报告全面且具备必定的权威性
2. 提供解决方案
3. 发现大的性能问题
复制代码
缺点:api
1.存在「波动」,不一样时刻的访客群体存在差别,数据只能反应当前时刻的「效果」
2.测试环境较单一,用户群体的环境各有不一样,不能够一律之
复制代码
将目标页面连接「委托」给第三方的服务,执行真实的访问指令,同时收集性能指标生成报表输出。数组
这种模式是在技术变现的背景下产生的,优秀的工具都是要付费的,固然开源和免费的优秀工具也不少,此前的阿里测就是其中一种,现已下线。停运的原因咱们很差揣测,此处谨向那些开源和提供免费服务的项目致敬!此处就再也不多推荐了,以避免有软文的嫌疑。浏览器
在目标页面注入脚本,在约定的时机收集性能指标数据,统一上报数据中心,数据中心集中整合生成报表,再根据报表分析性能。缓存
优势:
1. 数据全面,可采集到全部用户各个环境下的性能,生成直观的分布图
2. 数据真实,来源于真实用户
3. 反馈及时,优化后效果可及时地在报表上反馈出来
复制代码
缺点:
依赖较多,数据中心和脚本都须要自主开发,相对成本较高
复制代码
所谓监控,实际上就是性能「真实跟踪」,虽然依赖较多,但对性能指标的反馈最为真实有效。如下咱们将围绕性能监控进行展开。
页面的加载有多快?加载时间为 X.XX 秒?
其实,好与坏,快与慢,都是很模糊的概念。咱们经常听到别人介绍,「咱们的页面白屏已经从 3s 优化到了 2s」,这种陈述的问题并非不真实,而是在于扭曲了事实。 加载白屏时间会因用户不一样而有很大的差别,具体取决于用户的设备性能以及网络情况。 咱们不能单纯地以单个数字的形式呈现白屏时间而忽略加载时间过长的用户。更况且,收集来的数据具备幸存者误差性。
下图是某页面统计来的在必定时间段内用户白屏时间分布直方图。能够直观反应出此页面的「性能」状况。
咱们能够说,「90% 的用户能够在 3s 内完成页面加载」,但「均值」或「中位数」仅能反应此页面的某一点的表现,由于任何一个时间段都不能表明所有。
而性能优化的目标能够是增长 1s 内的用户比重,也能够是将后面的用户尽量的集中在 1s-2s 之间。这些都是须要根据产品特色和目标灵活调整的。
咱们所须要收集且重点关注的指标,应该是能准确反应用户体验的指标。
体验 | 表现 | 指标 |
---|---|---|
是否发生? | 导航是否成功启动?服务器是否有响应? | 首次绘制(FP)/首次内容绘制(FCP) |
是否有用? | 是否已渲染能够与用户互动的足够内容? | 首次有效绘制(FMP)/主角元素计时 |
是否可用? | 用户能够与页面交互,仍是页面仍在忙于加载? | 可交互时间(TTI) |
是否使人愉快? | 交互是否顺畅而天然,没有滞后或卡顿? | 耗时较长的任务(在技术上不存在耗时较长的任务) |
如下时序屏幕截图直观地展现了用户体验点对应的指标,有助你们理解。
其中指标 FP 和 FCP 能够经过浏览器点 API 计算获取,而指标 FMP 和 TTI 因为并无标准化的定义,所以也很难有标准化点 API 输出, 部分缘由在于很难以通用的方式界定「有效」点。
除此关键指标以外,咱们同时也须要关注基础指标,以便分析出形成关键指标「数据难看」的影响点。如 DNS 解析耗时、TCP 链接耗时、网络请求耗时以及资源加载耗时等。
标准化定义的指标有如下几种
Performance.timing 是一个只读属性,返回 PerformanceTiming 对象,该对象包括了页面相关的性能信息。
startTime(navigationStart):在同一个浏览器上下文中,前一个网页(与当前页面不必定同域)unload 的时间戳,若是无前一个网页 unload ,则与 fetchStart 值相等
unloadEventStart:前一个网页(与当前页面同域)unload 的时间戳,若是无前一个网页 unload 或者前一个网页与当前页面不一样域,则值为 0
unloadEventEnd:和 unloadEventStart 相对应,返回前一个网页 unload 事件绑定的回调函数执行完毕的时间戳
redirectStart:第一个 HTTP 重定向发生时的时间。有跳转且是同域名内的重定向才算,不然值为 0
redirectEnd:最后一个 HTTP 重定向完成时的时间。有跳转且是同域名内的重定向才算,不然值为 0
fetchStart:浏览器准备好使用 HTTP 请求抓取文档的时间,这发生在检查本地缓存以前
domainLookupStart:DNS 域名查询开始的时间,若是使用了本地缓存(即无 DNS 查询)或持久链接,则与 fetchStart 值相等
domainLookupEnd:DNS 域名查询完成的时间,若是使用了本地缓存(即无 DNS 查询)或持久链接,则与 fetchStart 值相等
connectStart:HTTP(TCP) 开始创建链接的时间,若是是持久链接,则与 fetchStart 值相等,若是在传输层发生了错误且从新创建链接,则这里显示的是新创建的链接开始的时间
connectEnd:HTTP(TCP) 完成创建链接的时间(完成握手),若是是持久链接,则与 fetchStart 值相等,若是在传输层发生了错误且从新创建链接,则这里显示的是新创建的链接完成的时间
注意:这里握手结束,包括安全链接创建完成、SOCKS 受权经过
复制代码
secureConnectionStart:HTTPS 链接开始的时间,若是不是安全链接,则值为 0
requestStart:HTTP 请求读取真实文档开始的时间(完成创建链接),包括从本地读取缓存,链接错误重连时,这里显示的也是新创建链接的时间
responseStart:HTTP 开始接收响应的时间(获取到第一个字节),包括从本地读取缓存
responseEnd:HTTP 响应所有接收完成的时间(获取到最后一个字节),包括从本地读取缓存
domLoading:开始解析渲染 DOM 树的时间,此时 Document.readyState 变为 loading,并将抛出 readystatechange 相关事件
domInteractive:完成解析 DOM 树的时间,Document.readyState 变为 interactive,并将抛出 readystatechange 相关事件
注意:只是 DOM 树解析完成,这时候并无开始加载网页内的资源
复制代码
domContentLoadedEventStart:DOM 解析完成后,网页内资源加载开始的时间,文档发生 DOMContentLoaded事件的时间
domContentLoadedEventEnd:DOM 解析完成后,网页内资源加载完成的时间(如 JS 脚本加载执行完毕),文档的DOMContentLoaded 事件的结束时间
domComplete:DOM 树解析完成,且资源也准备就绪的时间,Document.readyState 变为 complete,并将抛出 readystatechange 相关事件
loadEventStart:load 事件发送给文档,也即 load 回调函数开始执行的时间,若是没有绑定 load 事件,值为 0
loadEventEnd:load 事件的回调函数执行完毕的时间,若是没有绑定 load 事件,值为 0
更多解释参见 W3C Recommendation - NavigationTiming 或 W3C Editor's Draft。
利用以上 API,咱们能够计算出细颗粒度的性能基础指标
基础指标 | 描述 | 计算方式 | 备注 |
---|---|---|---|
rs | 准备新页面耗时 | fetchStart - navigationStart | |
rdc | 重定向时间 | redirectEnd - redirectStart | |
dns | DNS 解析耗时 | domainLookupEnd - domainLookupStart | |
tcp | TCP 链接耗时 | connectEnd - connectStart | |
ssl | SSL 安全链接耗时 | connectEnd - secureConnectionStart | 只在 HTTPS 下有效 |
ttfb | Time to First Byte(TTFB),网络请求耗时 | responseStart - requestStart | TTFB 有多种计算方式,ARMS 以 Google Development 定义为准 |
trans | 数据传输耗时 | responseEnd - responseStart | |
dom | DOM 解析耗时 | domInteractive - responseEnd | |
res | 资源加载耗时 | loadEventStart - domContentLoadedEventEnd | 表示页面中的同步加载资源 |
fbt | 首包时间 | responseStart - domainLookupStart | |
fpt | First Paint Time, 首次渲染时间 / 白屏时间 | responseEnd - fetchStart | 从请求开始到浏览器开始解析第一批 HTML 文档字节的时间差 |
tti | Time to Interact,首次可交互时间(非准确,仅作参考) | domInteractive - fetchStart | 浏览器完成全部 HTML 解析而且完成 DOM 构建,此时浏览器开始加载资源 |
load | 页面彻底加载时间 | loadEventStart - fetchStart | load = 首次渲染时间 + DOM 解析耗时 + 同步 JS 执行 + 资源加载耗时 |
关于兼容性,可参考下图,绝大多数的浏览器已支持此 API,基本能够放心地使用在移动端
相对于以上基础指标,跟用户感觉关联最密切的可能就是各个「绘制(Paint)」时刻了,FP(First Paint),FCP(First Contentful Paint)以及 FMP(First Meaningful Paint)。
随着 SPA(单页面系统)的普及,单纯靠 PerformanceTiming 要准确地计算出各 Paint 的时间是很难的。庆幸是的,Chrome 60+ 带给咱们一个全新的 API,Paint Timing,它提供了抓取「页面」和「资源」耗时的能力。此 API 尚处在实验阶段,并无归入 W3C 的标准,因此,也仅仅是 webkit 内核的高版本浏览器才支持。聊胜于无。
Performance.getEntries() 方法以数组形式对网页中每个对象(脚本文件、样式表、图片文件等等)发出的请求进行统计记录,Paint 的就是其中的一种。咱们可使用方法 performance.getEntriesByType('paint')
轻松得到两个 PerformancePaintTiming 对象,对应的分别就是 FP 和 FCP。
更多关于 FP 和 FCP,能够参考此文 www.w3cplus.com/performance…
但关于 FMP,虽然 Chrome 的 Performance 工具已指示性地标出 FMP 的时间点,但依然未提供 API,部分原因可能就是「没法标准化」吧。
因为 Performance 的赋能,咱们没有必要在页面「最开始」就加载执行咱们的监控脚本,再小的文件也会阻塞首屏的绘制,可是,若是有依赖关系,如一些算法依赖于监控 DOM 的变化,仍是须要尽早进行初始化,因此时机应在 load 的先后,根据算法的须要进行调整,并无一个准确的方案。
数据收集到以后即是数据上报、处理
关于数据上报的成熟方案已有不少,「主动提交」,「反向代理」均可以,只要数据在不影响业务功能和性能的前提下完整地将上报到数据中心便可。
有了数据,咱们就能够有目的性的将数据处理成咱们须要的形式。
能够分析用户分布
横向比较,细查差别因果,总结经验。
也能够按时间纬度展开,嗅探时间或流量对性能的影响,也能够找到异常点,筛选出异常日志重点关注。
总之,能够将有限的数据玩出无限的可能!
以上,即是对性能监控的一些基础介绍,但愿对你有所帮助。
[1] 以用户为中心的性能指标
转载请标明出处
做者: 木羽 zwwill
首发地址:zwwill/blog#31