前端监控实践——FMP的智能获取算法

标签: 前端性能 监控 javascript | 发表时间:2018-11-21 18:01 | 作者:斑驳光影
出处:https://segmentfault.com/blogs

今天来给大家介绍下前端监控中一个特定指标的获取算法,有人会问,为啥就单单讲一个指标?这是因为,目前大部分的指标,比如白屏时间,dom加载时间等等,都能通过现代浏览器提供的各种api去进行较为精确的获取,而今天讲的这个指标,以往获取他的方式只能是通过逻辑埋点去获取它的值,因此在做一些前端监控时,需要根据业务需要去改变页面对这个值的埋点方式,会比较繁琐,恰巧最近刚刚好在做一些前端监控相关的项目,遇到这个问题时就在想,能不能通过一种无须埋点的方式,将这个值给获取到?倒腾了一段时间,终于把算法弄出来了,今天就来给大家介绍下————FMP(first meaning paint) 指标的智能获取算法

什么是FMP

解答这个问题之前,我们先来了解下现代前端监控性能的主要指标统计方法,在2013年之后,标准组织推出了 performance timing api ,如下图

这个api统计了浏览器从网址开始导航到 window.onload事件触发的时间点,比如请求开始的时间点—— requestStart,响应结束的时间点—— responseEnd,通过这些时间点我们可以计算出一些对页面加载质量有指导意见的时长,比如以下几个:

  • TTFB : ResponseStart - RequestStart (首包时间,关注网络链路耗时)
  • FPT : ResponseEnd - FetchStart (首次渲染时间 / 白屏时间)
  • TTI : DomInteractive - FetchStart (首次可交付时间)
  • Ready : DomContentLoadEventEnd - FetchStart (加载完成时间)
  • Load : LoadEventStart - FetchStart (页面完全加载时间)

通过这些指标我们可以得到很多有用的web端网页加载信息,建立对网页性能概况

以上的指标可以对网页进行数值化的衡量,但是其实这种衡量只能体现一个视角的性能观点,比如TTFB很快,就能代表用户能够很快的看到页面的内容嘛?这个不一定是成立的,因此人们有开始从用户的视角去分析网页加载的性能情况,将用户看待加载过程,分成了以下几个阶段:

  • 页面是否正在正常加载 (happening)
  • 页面加载的内容是否已经足够(useful)
  • 页面是否已经可以操作了 (usable)
  • 页面是否可以交互,动画是否顺畅(delightful)

而我们今天讨论的 FMP(first meaningful paint),其实就是回答 is it useful,加载的内容是否已经足够,其实这是一个很难被定义的概念。每个网页都有自己的特点,只有开发者和产品能够比较确定哪个元素加载的时间点属于 FMP,今天我们就来讨论一下,如何比较智能的去找出页面那个主要的元素,确定页面的 FMP

成为FMP元素的条件

首先我们可以看看下面的图:

我们可以发现在页面中比较 useful的内容,都是含有信息量比较丰富的,比如图片,视频,动画,另外就是占可视面积较大的,页面中还存在两种形态的内容可以被视为是 useful的,一种是单一的块状元素,另外一种是由多个元素组合而成的大元素,比如视频元素,banner图,这种属于单一的块状元素,而像图片列表,多图像的组合,这种属于元素组合
总结一下成为FMP元素的条件:

  • 体积占比比较大
  • 屏幕内可见占比大
  • 资源加载元素占比更高(img, svg , video , object , embed, canvas)
  • 主要元素可能是多个组成的

算法如何设计

前面介绍了 FMP的概念还有成为 FMP的条件,接下来我们来看看如何设计 FMP获取的算法,按照上面的介绍,我们知道算法分为以下两个部分:

  1. 获取 FMP元素
  2. 计算 FMP元素的加载时间

如果有了解过浏览器加载原理的同学都知道,浏览器在在获取到html页面之后会逐步的对html文档进行解析,遇到javascript会停止html文档的解析工作,执行javascript,执行完继续解析html,直到整个页面解析完成为止。页面除了html文档中的元素加载,可能在执行javascript的时候,会产生动态的元素片段加载,一般来说,首屏元素会在这期间加载。因此我们只需要监控元素的加载和加载的时间点,然后再进行计算。

具体的算法流程如下图

相关的代码链接我已经放在最后面了,下面我会逐步的讲解整个算法流程

我把整个流程分为两个下面两个部分:

  1. 监听元素加载,主要是为了确定普通元素加载的时间点
  2. 确定 FMP元素,计算出最终的 FMP

下面我们按照步骤来分析

初始化监听

  • 可以看到首先我们先执行了 firstSnapshot方法,用于记录在代码执行之前加载的元素的时间点
  • 接下来初始化 MutationObserver,开始监听 document的加载情况,在发生回调的时候,记录下当前到 performance.timing.fetchStart的时间间隔,然后对body的元素进行深度遍历,进行打点,记录是在哪一次回调的时候记录的,如下图

  • 监听的最后我们会将在 window.onload的时候去触发检查是否停止监听的条件,如下图


如果监听的时间超过 LIMIT,或者发生回调的时间间隔已经超过1s中,我们认为页面已经稳定,停止dom元素加载的监听,开始进入计算过程

完成监听,进行元素得分计算

  • 首先前面我们说了,我们的元素对于页面的贡献是不同的,资源加载的元素会对用户视觉感官的影响比较大,比如图片,带背景的元素,视频等等,因此我设计了一套权重系统,如下:


可以看到 svg, img的权重为2, canvas, object, embed, video的权重为4,其他的元素为1,
也就是说,如果一个图片面积为1/2首屏面积,其实他的影响力会和普通元素占满首屏的影响力一样

  • 接着我们回到代码,我们首先会对整个页面进行深度优先遍历搜索,然后对每一个元素进行进行分数计算,如下图


可以看到我们通过 element.getBoundingClientRect获取了元素的位置和大小,然后通过计算 "width * height * weight * 元素在viewport的面积占比"的乘积,确定元素的最终得分,然后将改元素的子元素得分之和与其得分进行比较,去较大值,记录得分元素集

通过计算确定 FMP元素,计算最终 FMP时间

通过上面的步骤我们获取到了一个集合,这个集合是"可视区域内得分最高的元素的集合",我们会对这个集合的得分取均值,然后过滤出在平均分之上的元素集合,然后进行时间计算

可以看到分为两种情况去处理:

  1. weight为1的普通元素,那么我们会通过元素上面的标记,去查询之前保存的时间集合,得到这个元素的加载时间点
  2. weight不为1的元素,那么其实就存在资源加载情况,元素的加载时间其实是资源加载的时间,我们通过 performance.getEntries去获取对应资源的加载时间,获取元素的加载速度

最后去所有元素最大的加载时间值,作为页面加载的 FMP时间

最后

以上就是整个算法的比较具体的流程,可能有人会说,这个东西算出来的就是准确的么?这个算法其实是按照特征分析,特定的规则总结出来的算法, 总体来说还是会比较准确,当然web页面的布局如果比较奇特,可能是会存在一些偏差的情况。也希望大家能够一起来丰富这个东西,为 FMP这个计算方法提出自己的建议
附上代码 链接

相关 [前端 监控 实践] 推荐:

监控平台前端SDK开发实践

- - 美团点评技术团队
监控是提高故障处理能力和保障服务质量必需的一环,它需要负责的内容包括:及时上报错误、收集有效信息、提供故障排查依据. 及时上报错误:发生线上问题后,经由运营或者产品反馈到开发人员,其中流转过程可能是几分钟甚至几十分钟,这段时间可能直接导致公司的经济损失. 如果有一个监控系统,在线上出现问题时,监控系统能够第一时间报警,并且通知到开发人员,那开发人员就可以第一时间修复上线,使公司损失最小化.

前端监控实践——FMP的智能获取算法

- - SegmentFault 最新的文章
今天来给大家介绍下前端监控中一个特定指标的获取算法,有人会问,为啥就单单讲一个指标. 这是因为,目前大部分的指标,比如白屏时间,dom加载时间等等,都能通过现代浏览器提供的各种api去进行较为精确的获取,而今天讲的这个指标,以往获取他的方式只能是通过逻辑埋点去获取它的值,因此在做一些前端监控时,需要根据业务需要去改变页面对这个值的埋点方式,会比较繁琐,恰巧最近刚刚好在做一些前端监控相关的项目,遇到这个问题时就在想,能不能通过一种无须埋点的方式,将这个值给获取到.

前端性能监控系统ShowSlow

- - CSDN博客Web前端推荐文章
作者:zhanhailiang 日期:2014-11-14. ShowSlow是开源的前端性能监控系统,提供了以下功能:. 前端性能指标数据收集功能:ShowSlow原生提供了数据收集工具. DOM Monster!,但也支持通过YSlow,PageSpeed等第三方工具将性能数据上报给服务端完成收集(其服务器端提供了针对多达8种不同工具上报的数据收集器dommonster,dynatrace,events,har,metric,pagespeed,webpagetest,yslow);.

搭建前端异常监控系统

- - 掘金 架构
收集前端错误(原生、React、Vue). 利用Egg.js编写一个错误日志采集服务. 编写webpack插件自动上传sourcemap. 利用sourcemap还原压缩代码源码位置. 代码上线打包将sourcemap文件上传至错误监控服务器. 发生错误时监控服务器接收错误并记录到日志中. 根据sourcemap和错误日志内容进行错误分析.

前端监控系统设计

- - 掘金 前端
前言: 创建一个可随意插拔的插件式前端监控系统. 使用window.addEventListener('error',cb). 由于这个方法会捕获到很多error,所以我们要从中筛选出静态资源文件加载错误情况,这里只监控了js、css、img. // 捕获静态资源加载失败错误 js css img window.addEventListener('error', e => {.

Web前端优化最佳实践

- Jimmy - 中文热文榜|最新
还有 Jason, Bixuan, 曦, 推荐,查看全部 8 个推荐. 博评 - Sting的网经发表于2010-08-08 08:41:10. Google的前端优化最佳实践 Yahoo的前端优化最佳实践. Web前端优化最佳实践之Content篇. 尽量减少 HTTP 请求 (Make Fewer HTTP Requests).

前端性能优化最佳实践

- - Web前端 - ITeye博客
如今浏览器能够实现的特性越来越多,并且网络逐渐向移动设备转移,使我们的前端代码更加紧凑,如何优化,就变得越来越重要了. 开发人员普遍会将他们的代码习惯优先于用户体验. 但是很多很小的改变可以让用户体验有个飞跃提升,所以任何一点儿小小的优化都会提升你网站的性能. 前端给力的地方是可以有许多种简单的策略和代码习惯让我们可以保证最理想的前端性能.

前端组件化开发实践

- - 美团技术团队
随着前端开发复杂度的日益提升,组件化开发应运而生,并随着 FIS、React 等优秀框架的出现遍地开花. 这一过程同样发生在美团,面临业务规模的快速发展和工程师团队的不断扩张,我们历经引入组件化解决资源整合问题、逐步增强组件功能促进开发效率、重新打造新一代组件化方案适应全栈开发和共享共建等阶段,努力“controlling complexity”.

Puppeteer前端自动化测试实践

- - SegmentFault 最新的文章
本篇内容将记录并介绍使用Puppeteer进行自动化网页测试,并依靠约定来避免反复修改测试用例的方案. 主要解决页面众多时,修改代码导致的牵连错误无法被发现的运行时问题. 目前我们在持续开发着一个几十个页面,十万+行代码的项目,随着产品的更迭,总会出现这样的问题. 在对某些业务逻辑或者功能进行添加或者修改的时候(尤其是通用逻辑),这些通用的逻辑或者组件往往会牵扯到一些其他地方的问题.

前端异常监控解决方案研究

- - 腾讯CDC
前端监控包括行为监控、 异常监控、性能监控等,本文主要讨论异常监控. 对于前端而言,和后端处于同一个监控系统中,前端有自己的监控方案,后端也有自己等监控方案,但两者并不分离,因为一个用户在操作应用过程中如果出现异常,有可能是前端引起,也有可能是后端引起,需要有一个机制,将前后端串联起来,使监控本身统一于监控系统.