最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 统计页面首屏时间,很多人第一步就错了

    正文概述 掘金(大转转FE)   2021-02-14   529

    前言

    前端页面性能对用户留存、用户直观体验有着重要作用。这样的话如何更好的监控前端页面性能就变的十分重要。前端页面的性能监控主要分为两个方式:

    一种叫做合成监控 Synthetic Monitoring, SYN。就是在一个模拟场景里,提交一个需要做性能审计的页面,通过一系列的工具、规则去运行页面,提取一些性能指标,得出一个审计报告。合成监控中最近比较流行的是 GoogleLighthouse

    另一种是真实用户监控Real User Monitoring,RUM。监控真实的用户访问数据,上报数据到服务器,然后经过数据清洗加工,得到最终的性能数据。

    在前端性能监控中有一个非常重要的指标就是首屏时间,因为首屏时间直接反应了用户多久能看到页面的主要内容,这决定了用户体验。这样的话,如何取到准确的首屏时间对我们来说就变的非常重要。本文就结合之前的实践,聊一聊首屏时间如何计算。

    Performance

    在 SSR(服务端渲染)的应用中,我们认为htmlbody渲染完成的时间就是首屏时间。我们通常使用 W3C 标准的Performance对象来计算首屏时间。

    Performance经常被用于采集性能数据,因为对象内置了几乎所有常用前端需要的性能参数。

    统计页面首屏时间,很多人第一步就错了

    Performance包含了四个属性:memorynavigationtimeOrigintiming,以及一个事件处理程序onresourcetimingbufferfull。下面我们简单介绍一下Performanceapi

    memory

    memory这个属性提供了一个可以获取到基本内存使用情况的对象MemoryInfo

    performance.memory = {
      jsHeapSizeLimit, // 内存大小限制,单位是字节B
      totalJSHeapSize, // 可使用的内存大小,单位是字节B
      usedJSHeapSize   // JS对象占用的内存大小,单位是字节B
    }
    

    navigation

    返回PerformanceNavigation对象,提供了在指定的时间段发生的操作相关信息,包括页面是加载还是刷新、发生了多少重定向等。

    performance.navigation = {
      redirectCount: '',
      type: ''
    }
    

    timeOrigin

    返回性能测量开始的时间的高精度时间戳

    timing

    返回 PerformanceTiming 对象,包含了各种与浏览器性能相关的数据,提供了浏览器处理页面的各个阶段的耗时。下面是常用时间点计算

    window.onload = function() {
      var timing  = performance.timing;
      console.log('准备新页面时间耗时: ' + timing.fetchStart - timing.navigationStart);
      console.log('redirect 重定向耗时: ' + timing.redirectEnd  - timing.redirectStart);
      console.log('Appcache 耗时: ' + timing.domainLookupStart  - timing.fetchStart);
      console.log('unload 前文档耗时: ' + timing.unloadEventEnd - timing.unloadEventStart);
      console.log('DNS 查询耗时: ' + timing.domainLookupEnd - timing.domainLookupStart);
      console.log('TCP连接耗时: ' + timing.connectEnd - timing.connectStart);
      console.log('request请求耗时: ' + timing.responseEnd - timing.requestStart);
      console.log('白屏时间: ' + timing.responseStart - timing.navigationStart);
      console.log('请求完毕至DOM加载: ' + timing.domInteractive - timing.responseEnd);
      console.log('解释dom树耗时: ' + timing.domComplete - timing.domInteractive);
      console.log('从开始至load总耗时: ' + timing.loadEventEnd - timing.navigationStart);
    }
    

    通过上面的介绍, 我们可以轻松的得到首屏时间

    domLoadedTime = timing.domContentLoadedEventStart - timing.navigationStart
    

    FMP

    但是随着 VueReact等前端框盛行, 导致Performance无法准确的监控到页面的首屏时间。因为页面的body是空,浏览器需要先加载js, 然后再通过js来渲染页面内容。那我们使用什么数据来当做首屏时间呢?

    Lighthouse中我们可以得到 FMP 值,FMP(全称 First Meaningful Paint,翻译为首次有效绘制)表示页面的主要内容开始出现在屏幕上的时间点,它是我们测量用户加载体验的主要指标。我们可以认为FMP的值就是首屏时间,但是浏览器并没有把FMP的数据提供出来。那我们如何计算呢?

    整个计算流程分为两个下面两个部分: 1、监听元素加载,主要是为了计算Dom的分数 2、计算分数的曲率,计算出最终的FMP

    初始化监听

    initObserver() {
      try {
        if (this.supportTiming()) {
          this.observer = new MutationObserver(() => {
            let time = Date.now() - performance.timing.fetchStart;
            let bodyTarget = document.body;
            if (bodyTarget) {
              let score = 0;
              score += calculateScore(bodyTarget, 1, false);
              SCORE_ITEMS.push({
                score,
                t: time
              });
            } else {
              SCORE_ITEMS.push({
                score: 0,
                t: time
              });
            }
          });
        }
    
        this.observer.observe(document, {
          childList: true,
          subtree: true
        });
    
        if (document.readyState === "complete") {
          this.mark = 'readyState';
          this.calFinallScore();
        } else {
          window.addEventListener(
            "load",
            () => {
              this.mark = 'load';
              this.calFinallScore();
            },
            true
          );
          window.addEventListener(
            'beforeunload',
            () => {
              this.mark = 'beforeunload';
              this.calFinallScore();
            },
            true
          )
          const that = this;
          function listenTouchstart() {
            if(Date.now() > 2000) {
              that.calFinallScore();
              this.mark = 'touch';
              window.removeEventListener('touchstart', listenTouchstart, true);
            }
          }
          window.addEventListener(
            'touchstart',
            listenTouchstart,
            true
          )
        }
      } catch (error) {}
    }
    

    我们通过MutationObserver来监听Dom的变化, 然后计算当前时刻Dom的分数。有人可能会问,如果Dom每一次变化,都进行监听,是不是会特别消耗页面的性能?其实MutationObserver在执行回调时是批量执行,有些类似Vue等前端框架的渲染过程。

    计算分数

    function calculateScore(el, tiers, parentScore) {
      try {
        let score = 0;
        const tagName = el.tagName;
        if ("SCRIPT" !== tagName && "STYLE" !== tagName && "META" !== tagName && "HEAD" !== tagName) {
          const childrenLen = el.children ? el.children.length : 0;
          if (childrenLen > 0) for (let childs = el.children, len = childrenLen - 1; len >= 0; len--) {
            score += calculateScore(childs[len], tiers + 1, score > 0);
          }
          if (score <= 0 && !parentScore) {
            if (!(el.getBoundingClientRect && el.getBoundingClientRect().top < WH)) return 0;
          }
          score += 1 + .5 * tiers;
        }
        return score;
      } catch (error) {
    
      }
    }
    

    通过上面的代码,我们可以得到计算分数的步骤

    1、从body元素开发递归计算 2、会排查无用的元素标签比较SCRIPT等 3、如果元素超出屏幕就认为是 0 分 4、第一层的元素是 1 分,第二次的元素是 1 + (层数 * 0.5),也就是 1.5 分,依次类推,最终得打整个Dom数的总体分数

    计算出 FMP

    我们通过MutationObserver得到了一个数组,数组的每一项就是每次Dom变化的时间和分数。那么我们怎么计算出想要的FMP的值呢?

    let fmps = getFmp(SCORE_ITEMS);
    let record = null
    for (let o = 1; o < fmps.length; o++) {
      if (fmps[o].t >= fmps[o - 1].t) {
        let l = fmps[o].score - fmps[o - 1].score;
        (!record || record.rate <= l) && (record = {
          t: fmps[o].t,
          rate: l
        });
      }
    }
    

    通过上面的代码,我们会得到最终的FMP的值,就是变化最大的这个DOM变化。

    统计页面首屏时间,很多人第一步就错了

    总结

    到这里我们就基本把首屏时间的计算方式介绍完毕。总结为一句话,就是SSR使用Dom渲染结束的时间,SPA的项目使用FMP的时间。

    本月文章预告

    预告下,接下来我们会陆续发布转转在多端 SDK、移动端等基础架构和中台技术相关的实践与思考,欢迎大家关注公众号 “大转转 FE”,期望与大家多多交流


    起源地下载网 » 统计页面首屏时间,很多人第一步就错了

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元