性能优化——window.performance监测载入白屏时间

2,451 阅读3分钟

「这是我参与2022首次更文挑战的第1天,活动详情查看:2022首次更文挑战」。

前言

领导:"小凌,可以优化下项目的白屏时间么?",最近接到这么一个关于性能优化的任务。解决问题的第一步是要先复现问题。可是页面的白屏时间怎么计算呢?小凌首先想到的是浏览器调试工具下的Performance

1.png

在之前看过一个讲座,讲的是window.performance对性能的监控。于是便对这个进行了进一步研究。

performance的作用

是浏览器暴露给js的一个接口,可以通过这个接口查看用户访问网站的连接建立时间、dns时间等信息。使用该api时需要在页面完全加载完成之后才能使用,最简单的办法是在window.onload事件中读取各种数据,因为很多值必须在页面完全加载之后才能得出。

performance.timing属性介绍

下面的图大家一定不陌生:

2.png

属性说明:

  • navigationStart:浏览器处理当前网页的启动时间
  • fetchStart:浏览器发起http请求读取文档的毫秒时间戳。
  • domainLookupStart:域名查询开始时的时间戳。
  • domainLookupEnd:域名查询结束时的时间戳。
  • connectStart:http请求开始向服务器发送的时间戳。
  • connectEnd:浏览器与服务器连接建立(握手和认证过程结束)的毫秒时间戳。
  • requestStart:浏览器向服务器发出http请求时的时间戳。或者开始读取本地缓存时。
  • responseStart:浏览器从服务器(或读取本地缓存)收到第一个字节时的时间戳。
  • responseEnd:浏览器从服务器收到最后一个字节时的毫秒时间戳。
  • domLoading:浏览器开始解析网页DOM结构的时间。
  • domInteractive:网页dom树创建完成,开始加载内嵌资源的时间。
  • domContentLoadedEventStart:网页DOMContentLoaded事件发生时的时间戳。
  • domContentLoadedEventEnd:网页所有需要执行的脚本执行完成时的时间,domReady的时间。
  • domComplete:网页dom结构生成时的时间戳。
  • loadEventStart:当前网页load事件的回调函数开始执行的时间戳。loadEventEnd:当前网页load事件的回调函数结束运行时的时间戳。

计算性能指标

可以使用Navigation.timing 统计到的时间数据来计算一些页面性能指标,比如DNS查询耗时白屏时间domready等等。如下:

  • DNS查询耗时 = domainLookupEnd - domainLookupStart
  • TCP链接耗时 = connectEnd - connectStartrequest
  • 请求耗时 = responseEnd - responseStart
  • 解析dom树耗时 = domComplete - domInteractive
  • 白屏时间 = domLoading - fetchStart
  • domready时间 = domContentLoadedEventEnd - fetchStart
  • onload时间 = loadEventEnd - fetchStart

计算性能工具类

我们可以利用上面讲的特性来建立我们自己的性能计算工具类

timing.js

(function () {
  function handleAddListener(type, fn) {
    if (window.addEventListener) {
      window.addEventListener(type, fn);
    } else {
      window.attachEvent('on' + type, fn);
    }
  }
  function getTiming() {
    try {
      var time = performance.timing;
      var timingObj = {};
      var loadTime = (time.loadEventEnd - time.loadEventStart) / 1000;
      if (loadTime < 0) {
        setTimeout(function () {
          getTiming();
        }, 200);
        return;
      }
      timingObj['重定向时间'] = (time.redirectEnd - time.redirectStart) / 1000;
      timingObj['DNS解析时间'] = (time.domainLookupEnd - time.domainLookupStart) / 1000;
      timingObj['TCP完成握手时间'] = (time.connectEnd - time.connectStart) / 1000;
      timingObj['HTTP请求响应完成时间'] = (time.responseEnd - time.requestStart) / 1000;
      timingObj['DOM开始加载前所花费时间'] = (time.responseEnd - time.navigationStart) / 1000;
      timingObj['DOM加载完成时间'] = (time.domComplete - time.domLoading) / 1000;
      timingObj['DOM结构解析完成时间'] = (time.domInteractive - time.domLoading) / 1000;
      timingObj['脚本加载时间'] = (time.domContentLoadedEventEnd - time.domContentLoadedEventStart) / 1000;
      timingObj['onload事件时间'] = (time.loadEventEnd - time.loadEventStart) / 1000;
      timingObj['**白屏时间**'] = (time.domLoading - time.fetchStart) / 1000;
      timingObj['页面完全加载时间'] = timingObj['重定向时间'] + timingObj['DNS解析时间'] + timingObj['TCP完成握手时间'] + timingObj['HTTP请求响应完成时间'] + timingObj['DOM结构解析完成时间'] + timingObj['DOM加载完成时间'];
      Object.keys(timingObj).forEach((key) => {
        console.log(key + ':' + timingObj[key] + '毫秒(ms)');
      });
      console.log(performance.timing);
    } catch (e) {
      console.log(e);
      console.log(timingObj);
      console.log(performance.timing);
    }
  }
  handleAddListener('load', getTiming);
})();

index.html


<!DOCTYPE html>
<html lang="">
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width,initial-scale=1.0" />
    <link rel="icon" href="<%= BASE_URL %>favicon.ico" />
    <title>小凌爱前端</title>
  </head>
  <body>
    <div id="app"></div>
    <!--性能监测js-->
    <script type="text/javascript" charset="utf-8" src="timing.js"></script>
  </body>
</html>

如此我们便可以在首页种监听我们的性能变化了。

gif2.gif

浏览器兼容性

目前关于Window.performance.timing 的浏览器兼容性如下图所示:

3.png