前端性能监控

从一道经典的面试题开始

(本文部份内容整理自网络文章)html

用户从输入 URL 到页面加载完成,都发生了什么?前端

image

  1. DNS 解析 (解析域名,将URL解析为对应的IP地址)
  2. TCP 链接(与这个IP创建TCP网络链接,三次握手)
  3. 发送HTTP 请求
  4. 服务端相应HTTP 返回数据
  5. 浏览器拿到响应数据,解析响应内容,把解析的结果展现给用户

前端性能都包括哪些

image

这个性能划分是我从一篇文章上扒下来的,咱们这里主要讨论性能监控vue

前端性能监控-关键指标

  • 首屏时间
  • 白屏时间
  • 页面总下载时间

浏览器性能先关内容概述

性能方面咱们经过 window.preformance.timing 这个属性来获取性能相关参数react

window.preformance.timing(记录了页面各个状态的时间戳)面试

image

那么这些参数都是什么意义,以及它们触发机制是什么算法

我来看一张经典的图 canvas

image

咱们把它翻译一下数组

【Prompt for unload】- 用户跳转行为(在地址栏输入url后按回车,或者点击a标签跳转等)
 navigationStart、startTime // 当前浏览器窗口的前一个网页关闭开始执行的时间戳
 unloadStart // 前一个页面unload触发开始时间戳
【unload】- 前一个页面unload时间
 unloadEnd // 前一个页面unload触发结束时间戳
 redirectStart // 返回第一个HTTP跳转开始时的时间戳若是没有跳转,或者不是同一个域名内部的跳转,则返回值为0
【redirect】- 重定向
 redirectEnd // 返回最后一个HTTP跳转结束时(即跳转回应的最后一个字节接受完成时)的时间戳,若是没有跳转,或者不是同一个域名内部的跳转,则返回值为0
 fetchStart // 返回浏览器准备使用HTTP请求读取文档时的时间戳。该事件在网页查询本地缓存以前发生
【App cache】- 网页查询本地缓存
 domainLookupStart // 返回域名查询开始时的时间戳。若是使用持久链接,或者信息是从本地缓存获取的,则返回值等同于fetchStart属性的值
【DNS】- 域名查询
 domainLookupEnd // 返回域名查询结束时的时间戳。若是使用持久链接,或者信息是从本地缓存获取的,则返回值等同于fetchStart属性的值
 connectStart // 返回创建TCP连接开始向服务器发送时的时间戳。若是使用持久链接(persistent connection),则返回值等同于fetchStart属性的值
【TCP】
 secureConnectionStart // 它的值是安全链接握手以前的时刻。若是该属性不可用,则返回undefined。若是该属性可用,但没有使用HTTPS,则返回0
 connectEnd // 返回浏览器与服务器之间的链接创建时的时间戳。若是创建的是持久链接,则返回值等同于fetchStart属性的值。链接创建指的是全部握手和认证过程所有结束
回浏览器与服务器开始安全连接的握手时的时间戳。若是当前网页不要求安全链接,则返回0
 requestStart // 返回浏览器向服务器发出HTTP请求时(或开始读取本地缓存时)的时间戳
【Request】 - 网络请求
 responseStart // 返回浏览器从服务器收到(或从本地缓存读取)第一个字节时的时间戳
【Response】
 responseEnd // 返回浏览器从服务器收到(或从本地缓存读取)最后一个字节时(若是在此以前HTTP链接已经关闭,则返回关闭时)的时间戳
 domLoading // 返回当前网页DOM结构开始解析时(即Document.readyState属性变为“loading”、相应的readystatechange事件触发时)的时间戳
【Processing】
 domInteractive // 返回当前网页DOM结构结束解析、开始加载内嵌资源时(即Document.readyState属性变为“interactive”、相应的readystatechange事件触发时)的时间戳
 domContentLoadedEventStart // 返回当前网页DOMContentLoaded事件发生时(即DOM结构解析完毕、全部脚本开始运行时)的时间戳
 domContentLoadedEventEnd // 返回当前网页全部须要执行的脚本执行完成时的时间戳
 domComplete // 返回当前网页DOM结构生成时(即Document.readyState属性变为“complete”,以及相应的readystatechange事件发生时)的时间戳
 loadEventStart // 返回当前网页load事件的回调函数开始时的时间戳。若是该事件尚未发生,返回0
【onLoad】- window.onLoad触发
 loadEventEnd // 返回当前网页load事件的回调函数运行结束时的时间戳。若是该事件尚未发生,返回0。经过while循环持续判断直到loadEventEnd>0则表示彻底加载完毕了!网络再也不有任何数据请求、dom也渲染完毕了
复制代码

注意

因为window.preformance.timing是一个在不一样阶段,被不停修正的一个参数对象,因此,建议在window.onload中进行性能数据读取和上报浏览器

关键数据获取

  • 首屏时间:计算起来比较麻烦,后文会详述
  • 白屏时间:responseEnd - navigationStart
  • 页面总下载时间:loadEventEnd - navigationStart

其余数据:缓存

  • DNS解析耗时:domainLookupEnd - domainLookupStart
  • TCP连接耗时:connectEnd - connectStart
  • 首包请求耗时:responseEnd - responseStart
  • dom解释耗时:domComplete - domInteractive
  • 用户可操做时间:domContentLoadedEventEnd - navigationStart
  • ...

首屏时间计算

目前业内对首屏时间方式并不统一,常见的有下面几种计算方式:

  • 利用首屏中最后一张图片加载完成的时间来当作首屏时间(适合首屏元素由服务端渲染

方法:给页面全部的img绑定onload事件,用来记录图片加载时间;在window.onload中,计算每个img的offsetTop;把符合首屏高度的图片数据收集起来,计算最大onload时间

  • 图片类似度比较法,经过比较连续截屏图像的像素点变化趋势肯定首屏时间(适合异步请求数据渲染的场景

方法:经过html2canvas插件,每100ms截取屏幕;而后获取屏幕九宫格每一格中心点的,获取红色通道的像素相加获得一个值,经过不断截屏和比较这个求和的值,监控出首屏是否加载完毕。(截屏图像类似度比较的方法最为科学和直观,可是比较消耗本地设备的运行资源。并且因为比较复杂的运算,会影响到页面逻辑脚本执行的性能)

  • 首屏模块标签标记法(页面多数异步请求渲染)

方法:在 HTML 文档中对应首屏内容的标签结束位置,使用内联的 JavaScript 代码记录当前时间戳

  • 自定义模块内容计算法(自定义每一个页面太复杂)

方法:经过自定义模块内容,来简化计算首屏时间

  • 用onLoad或者domReady触发时间表示首屏时间

咱们的首屏计算方式

首先咱们要介绍一下window.performance.getEntries()方法,由于后面会用到

window.performance.getEntries()

调用后会获取页面加载资源和网络请求信息

image

拿到以后是个数组,里面包含了页面全部的静态资源、网络请求相关信息,咱们经过initiatorType来获取每个元素的属性

image

“xmlhttprequest”表示的就是接口请求

首屏计算方式

  • 默认值为:domContentLoadedEventEnd - navigationStart
  • 若是是vue项目,采用mounted触发时间做为计算分界点。
  • 若是是react项目,采用componentDidMount触发时间做为计算分界点。
  • 遍历window.performance.getEntries()全部内容,过滤mounted、componentDidMount以前发出的全部请求内容,若是有xmlhttprequest,则采用最后返回response的时间做为首屏时间
  • 若是是ssr项目,直接采用默认计算方式(domContentLoadedEventEnd - navigationStart)

可能你们会有疑问,咱们首屏时间的计算中,不包含渲染和图片加载时间?

确实,咱们这么作有两个前提:

  • 一般状况下咱们认为浏览器渲染时间会很快
  • 页面加载的图片必须进行截取(这个由各业务线本身控制)

因此这种首屏计算方式,更像是“首屏数据开始渲染时间”(由于此时已经拿到了首屏渲染全部须要的数据)

在图片过多、过大时候是会有必定程度的偏差

咱们为何这么作?

  • 为了实现自动统计,且不但愿性能统计的逻辑被强制注入到的业务代码中
  • 尽量的接近真实的首屏加载时间
  • 在不过多占用浏览器首屏加载性能的状况下完成数据收集

首屏时间目前各家公司的计算方式不尽相同,可是所采用的,必定是在符合各自公司真实状况的前提下,最接近于首屏时间的计算方式。

其实数据准确性和收集数据的性能开销,是一种博弈,对于公司来说,应该选择最合适的方式。

相关文章
相关标签/搜索