【性能】Performance 页面性能分析

  • 2019 年 11 月 12 日
  • 笔记

后面会把前端进阶的课程内容都总结一遍。有些都是很常见的知识,但是为了梳理自己的知识树,所以尽量模糊的地方都会记录

笔记列表在公众号右下角

平常我们总说性能优化,性能优化,也懂个什么文件压缩,雪碧图什么的

但是你根本还是不清楚你性能优化的程度,不知道你网站的性能如何就像盲目地填一个不知道多深的坑,如此没有目的性的优化必然浪费大量精力而得不到想要的结果

所以填坑须知坑有多深,性能优化须知性能如何

那么怎么知道你的网站性能如何呢?答案就是使用 window.performance!

Performance 简介

为了解决网页性能测试的困难,更加精确地测量和提高网页和 web 程序的性能

W3C 和各大浏览器厂商共同制定了 Web Performance API

通过 performance 我们可以做什么?

可以查看用户访问网站的各项性能数据,比如

1、连接建立的时间

2、DNS 解析的时间

3、网站内容响应的时间

4、各项图片的加载时间

等等等等

我们通常会怎么衡量网站的性能?

比如说,

1、什么时候页面开始展示?

2、什么时候首屏内容展示完毕?

如果你的网站打开速度太慢,那么就会流失很多用户。这两个指标就可以衡量你网站速度的性能

那么我们怎么通过 performance 去得到这两个指标?performance 有很多 api,下面我们就来一个个看

Performance API

我们先去控制台打印一下这个 performance

咦惹,看到performance 是个对象哦,看到里面还有挺多字段的

memory,navigation,timeOrigin,timing ,onresourcetimingbufferfull

五个字段其中最常用的就是前面四个字段了,我们也是主要用这四个字段去测量网站的性能下面来仔细看下把

1performance.memory

通过这个字段可以获取浏览器的内存情况,但是这个不是标准的performance 属性,只存在 谷歌浏览器中memory 还存在下面几个属性

usedJSHeapSize,表示被使用的 JS 堆栈内存

totalJSHeapSize,表示当前 JS 堆栈内存总大小

jsHeapSizeLimit,表示内存大小限制

其中,usedJSHeapSize 不能大于 totalJSHeapSize,否则会出现内存泄漏的情况

我特地去了几个大网站看他们的内存使用情况

这是京东的

这是淘宝的

发现 jsHeapSizeLimit 应该是浏览器总的内存限制

然后给每个网站分配的内存大小都不一样,也不知道是怎么分的

2performance.navigation

通过这个字段,可以知道页面加载的原因,什么意思呢?就是你是怎么进入这个页面的,是刷新啊,点了链接进来啊之类的

navigation 同样存储了两个属性,保存触发页面加载的原因

这两个字段都是数字啊,我们来分别看看他们的意思

我们来玩下

点击链接

刷新

点击历史记录的连接

redirectCount

表示到达当前页面,经过重定向的次数

下面我们将会介绍一个 performance.timing 属性,请问你做好准备了吗?内容很多哦,这个属性,请你做好十足心里准备再来挑战哦

3performance.timing

timing 是一个对象,包含了很多属性

介个对象非常重要啊,包含了各种浏览器性能相关的信息

比如说网站建立连接,DNS查询等各种数据从 timing ,你可以了解到网站各节点加载情况,可以更为全面的得了解网页性能的详细情况你可以通过这些属性,计算出页面的信息

比如

1、页面经历了多长时间

2、网页加载的耗时

3、DNS 解析耗时

4、TCP 连接耗时

5、TTFB 获取首字节 耗时

先来打印整体看一下

你也看到了,很多东西的,但是表示的都是【时间】,并且单位都是【毫秒】

并且同一类型的东西有起始时间和结束时间两个,他们表示的只是整个过程中记录的时间点位置而已

用一个大图来整体看一下,然后再仔细记录每个过程的时间点

下图主要是记录了哪个过程的起始和结束时间点

看完大图,我们按类别把这些属性给分一下

1、域名相关

domainLookupStart , 域名开始查询的时间

domainLookupEnd , 域名查询结束的时间

2、连接相关

fetchStart

准备好使用 http 请求 页面文档 的时间,但是并不是此时发送 http

你输入了 url,按下回车,浏览器收到指令需要发起请求(此时只是记录了时间点,没有发起请求)

浏览器不会马上发出请求,如上面那个长图,会先去看有没有命中的缓存,然后进行 DNS 查询

connectStart、connectEnd

-start ,就是 浏览器开始和 服务器建立 TCP连接的时间

-end,就是浏览器和服务器 成功建立TCP连接的时间。建立连接指的是所有握手和 认证过程的总时间

我们都知道,服务器和浏览器通信之前需要建立 TCP 连接,会可以在此之上发送 http 报文

所以在 成功建立连接之前,浏览器都不会发送 http 请求

fetchStart 和 connectStart 的区别

仔细观察这两个值,有时一样,有时不一样,是为什么呢?

因为 TCP 长连接的原因,当我们第一次加载页面的时候,需要建立 TCP 连接,所以此时 fetchStart ≠ connectStart 以 segmentfault 为例

第一次加载后获取时间点如下

而当我们刷新页面的时候,他们变成一样的了

当我过一段时间再刷新,他们又不一样了

如果我紧接着关闭浏览器再打开,他们还是不一样的这是为什么?

当 TCP 建立连接后,第一次需要消耗时间建立连接,所以 fetchStart ≠ connectStart

而后面的请求则会复用这个 TCP 连接,所以刷新之后,fetchStart = connectStart

就算你关闭了页面,TCP 连接依然存在,再打开页面,两者依然相等

但是如果一段时间无交互,TCP 连接就会断开,那么再次刷新需要重连,所以两者又不一样而关闭浏览器,会立即断开 TCP 连接

secureConnectionStart

不一定需要这个值。如果当前协议是 https,那么会得到 开始 SSL握手的时间,如果不是 https,那么就是0

requestStart

浏览器向 服务器开始发送http 请求时的时间(或开始读取本地缓存的时间)

responseStart、responseEnd

-start,就是浏览器从服务器收到第一个字节的时间(或本地缓存返回第一个字节的时间)

-end,就是浏览器从服务器收到最后一个字节的时间(或本地缓存读取最后一个字节的时间)

3、事件相关

unloadEventStart,unloadEventEnd

-start , 同一域名,前一个网页 unload 事件开始触发的时间。

-end,同一域名,前一个网页 unload 事件触发结束的时间。如果不是同一域名下的网页跳转,或者没有前一网页,那么值为0

loadEventStart,loadEventEnd

-start,当前网页 load 事件开始触发的时间。如果 load 没有触发,那么值是0

-end,当前网页 load 事件触发结束的时间。如果 load 没有触发,那么值是0

domContentLoadedEventStart,domContentLoadedEventEnd

-start,当前网页 DOMContentLoaded 事件开始触发的时间

-end,当前网页 DOMContentLoaded 事件触发结束的时间,网页内部所有资源加载完毕,包括 JS 执行完毕

4、文档解析相关

domLoading

当前网页 开始解析 DOM 结构的时间Document.readyState 变化 loading,readystatechange 事件被触发

domInteractive

当前网页 解析完毕 DOM 结构 ,开始加载内嵌资源的时间这里只是 DOM 树解析完,还没有加载网页内的资源,比如图片等Document.readyState 变化 interactive,readystatechange 事件被触发

domComplete

当前网页 文档解析完成的时间Document.readyState 变化 complete,readystatechange 事件被触发

5、跳转相关

navigationStart

浏览器前一个网页关闭,发送 unload 事件的时间

navigationStart 和 unloadEventStart 的区别

这两个意思很像啊,感觉会有点搞混,但是其实 navigationStart 取值先于 unloadEventStart

并且!

navigationStart 不限域,就是说,跨域的跳转也存在值,而 unloadEventLoad 必须是同域下的跳转才有值

navigationStart 和 fetchStart 的区别

W3C 说如果没有上一个文档,那么这两个值相同,但是我怎么测都没有测到一样的,最多是近似一样

redirectStart、redirectEnd

-start,当前页面开始重定向的时间,需要同一个域名下的重定向,否则值为0

-end,当前页面结束重定向的时间,需要同一个域名下的重定向,否则值为0

我们现在就来测一下不同域下的情况

计算相关节点

上面我们介绍了这么多属性,那我们到底要怎么使用他们去得到我们想要的数据呢?

我们是需要通过上面的属性进行计算,用来得到网页相关的信息

1、页面经历多长时间

从浏览器开始加载,到现在 经历的时间

Date.now() - performance.timing.navigationStart;

2、网页从开始到加载结束的耗时

performance.timing.loadEventEnd - performance.timing.navigationStart

3、DNS 域名解析耗时

performance.timing.domainLookupEnd - performance.timing.domainLookupStart;

4、TCP 连接耗时

performance.timing.connectEnd - performance.timing.connectStart;

5、获取到网页首字节的耗时

performance.timing.responseStart - performance.timing.navigationStart;

哎哟,timing 的内容到这里就结束了

performance 还有好多内容啊,下面接着来看多两个点就好了

4performance.now()

这是一个方法,会得到当前网页 从 performance.timing.navigationStart 到 当前时间的的 微秒数

微秒数就是 毫秒的 千分之一

performance.now() 近似等于 Date.now() , 但是一个是微秒,一个是毫秒,显然前者更加精确

5performance.getEntries()

这也是一个方法,返回一个数组

浏览器在获取网页时,网页中的每一个资源都会发起一个 http 请求,包括图片,JS,CSS 文件等

而 这个方法则会捕捉到这些所有的请求信息,然后返回给你

我们展开其中一个请求的信息

你看其中也包含了和 performance.timing 一样 密密麻麻各种节点的时间信息,包括发起请求,连接时间等等

我们主要看看其中五个属性

name,资源的名称

startTime,开始加载资源的时间

duration,资源加载耗时

entryType,资源的类型

initiatorType,请求发起者

上面的时间单位都是 毫秒

这五个属性,有两个是比较懵的,资源类型 和 请求发起者

资源类型 entryType

一般值 是 resource,像是 css 文件,js 脚本,img,http 请求 ,他们的资源类型都是 resource

请求发起者 intiatorType

值就有很多种,但是类型就只有四个,但是主要关注三个就行了

1、通过标签加载的资源

标签为载体发起的请求,值一般是小写标签,比如有, link,script,img,iframe 等

但是如果是 audio 和 video 加载的资源,intiatorType 不是 audio 和 video,谷歌返回空,火狐返回 other

2、通过css 文件加载的资源

比如 字体文件,背景图片等在 css 文件中内嵌而加载的资源,值为 css

如果一个背景图片也用过 img 加载,那么 initatorType 返回 img

3、通过 xhr 加载的资源

毫无疑问,就是向服务器获取数据时发起的请求,发起对象是 XMLHttpRequest,值是 xhlhttprequest 或者 fetch

好的,performance 暂时就记录到这里,其实他还是有一部分比较重要的内容的

但是鉴于文章篇幅不宜太长,而且另外一部分内容的作用跟本文不太一样

所以打算放到另一篇文章进行记录