前端修仙路-性能标准
我们写出来的网站离不开性能测试,那么如何衡量一个网站的性能呢?这就不得不说Performance这个api了, 它包含了各种网页加载期间的耗时。
我们先来认识一下Performance,长这个样子:
属性
memory => MemoryInfo 内存信息对象
- jsHeapSizeLimit 内存大小限制
- totalJSHeapSize 可使用的内存
- usedJSHeapSize js占用的内存(包含v8内部对象),<= totalJSHeapSize,
若大于则说明有内存泄漏
navigation => PerformanceNavigation 导航性能对象
- redirectCount 到达页面之前的重定向次数
- type 导航类型
- 0 普通进入,链接,url,表单
- 1 刷新进入
- 2 操作历史记录进入
- 255 其他类型进入
onresourcetimingbufferfull
当浏览器资源时间性能缓冲区已满时会触发的回调函数
timeOrigin
performance性能测试开始的时间的时间戳
timing => PerformanceTiming 性能时间对象
以下按照时间顺序排列(可以思考面试问到的问题,从输入一个地址,浏览器发生了什么?):
- navigationStart 前一个网页的unload时间(不管是同源还是非同源),没有则等于fetchStart
- unloadEventStart 同源,前一个网页unload开始时间,否则,值为0
- unloadEventEnd 同源,前一个网页unload完成时间,否则,值为0
- redirectStart 同源,第一个重定向开始时间,否则为0
- redirectEnd 同源,最后一个重定向完成时间,否则为0
- fetchStart 浏览器准备通过HTTP请求去获取页面的时间戳。在检查应用缓存之前发生。
- domainLookupStart DNS域名查询开始时间,持久链接或使用了缓存则与fetchStart相等
- domainLookupEnd DNS域名查询完成,持久链接或使用了缓存则与fetchStart相等
- connectStart 开始建立tcp链接时间,持久链接与fetchStart相等
- connectEnd 完成tcp连接建立时间(完成握手)
- secureConnectionStart HTTPS 连接开始的时间,如果不是,则值为 0
- requestStart 浏览器向服务器发出HTTP请求时(或开始读取本地缓存时)的时间戳
- responseStart 浏览器从服务器收到(或从本地缓存读取)第一个字节时的时间戳。
- responseEnd 浏览器从服务器收到(或从本地缓存读取)最后一个字节时(如果在此之前HTTP连接已经关闭,则返回关闭时)的时间戳
- domLoading 开始解析渲染 DOM 树的时间,
Document.readyState='loading'
- domInteractive 完成dom解析时间,准备加载内嵌资源,
Document.readyState='interactive'
。 - domContentLoadedEventStart DOM 解析完成后,网页内资源加载开始的时间,
DOMContentLoaded
事件准备触发,js脚本解析完毕 - domContentLoadedEventEnd DOM 解析完成后,网页内资源加载完成的时间,此时
DOMContentLoaded
事件已经触发,js脚本执行完毕时间(DOM Ready) - domComplete dom树解析完成,并且资源也就绪,
document.readyState='complete'
- loadEventStart onload开始触发时间
- loadEventEnd onload完成触发时间
方法
getEntries():Array<PerformanceNavigationTiming>
返回一个数组对象,含有css,img,script,xmlhttprequest,link等所有的加载时间。这个数组就是性能缓存区存储的数据。
getEntriesByName(name:string,type:string):Array
> performance.getEntriesByName('first-paint')
[PerformancePaintTiming]
0: PerformancePaintTiming {name: "first-paint", entryType: "paint", startTime: 422.34000004827976, duration: 0}
length: 1
__proto__: Array(0)
与getEntries类似,增加了name和type的筛选条件。
getEntriesByType(type:string):Array
> performance.getEntriesByType('paint')
(2) [PerformancePaintTiming, PerformancePaintTiming]
0: PerformancePaintTiming {name: "first-paint", entryType: "paint", startTime: 422.34000004827976, duration: 0}
1: PerformancePaintTiming {name: "first-contentful-paint", entryType: "paint", startTime: 422.34500008635223, duration: 0}
length: 2
__proto__: Array(0)
与getEntries类似,通过type的筛选条件获取。
mark(name:string):void
在浏览器的性能缓冲区中使用给定名称添加一个timestamp(时间戳) ,也就是自定义添加一个PerformanceMark对象,可以被以上三种方法检索到。
> performance.mark('test')
> performance.getEntriesByName('test')
[PerformanceMark]
0: PerformanceMark {name: "test", entryType: "mark", startTime: 24589856.25499999, duration: 0}
length: 1
__proto__: Array(0)
- startTime 调用mark的时间戳
- duration 0,没有持续时间
measure(name:string,startMarkName:string,endMarkName:string):void
测量两个mark之间所用时间。
performance.mark('test-start');
setTimeout(()=>{
performance.mark('test-end');
performance.measure('test','test-start','test-end');
console.log(performance.getEntriesByName('test'));
},1000)
/* 输出
PerformanceMeasure
duration: 12605.970000151545
entryType: "measure"
name: "test"
startTime: 25013398.659999948
__proto__: PerformanceMeasure
length: 3
__proto__: Array(0)
*/
clearMarks(name:string):void
清除mark,把mark从性能缓存区删去,不填name则清除所有mark
clearMeasures(name:string):void
清除measure测量,不填name则清除所有measure。
now()
当前时间与performance.timing.navigationStart的时间差,比Date.now()测量精准一些。
性能测量
这里说一下谷歌的性能指标:
- TTFB (Time To First Byte) 首绘时间(FP),浏览器绘制第一个像素点
- TTSR(Time to Start Render) 开始渲染时间,首次内容绘制时间(FCP),有一个元素开始渲染显示
- TTDC(Time to Document Complete) 文档加载完成时间
- TTFL(Time to Fully Loaded) 文档完全加载时间
我们比较关心的:
- FP(First Paint) 首绘时间
- FMP(First Meaningful Paint) 首次有效绘制,即主角元素绘制,如视频网站,则是视频开始绘制的时间。
- TTI(Time To Interactive) 用户可交互时间,视觉已经渲染,页面可以响应用户操作。
- FPS( Frames Per Second) 每秒帧率,小于30会感觉明显卡顿,50~60则非常流畅,一般用requestAnimationFrame进行优化,由系统决定执行时机,避免页面卡顿。
FPS的测量在chrom devtools里,打开方式:更多(三个点那里展开)=>more tools=>Rendering=>FPS meter,勾选这个选项,浏览器左上角就会出现FPS测量工具。也可以借用requestAnimationFrame这个api来手动计算。
常见的计算
- 内存占用:memory.usedJSHeapSize
- DNS查询耗时 :domainLookupEnd - domainLookupStart
- TCP链接耗时 :connectEnd - connectStart
- TTFB(Time To First Byte)收到第一个字节耗时:responseStart - navigationStart
- request请求耗时 :responseEnd - responseStart
- dom渲染耗时 : domComplete - domLoading
- TTI(Time To First Byte)用户可交互时间:domContentLoadedEventEnd - navigationStart
- 首屏加载时间:
- 有图:首屏内的图片最晚加载时间-navigatorStart
- 没图:domInteractive - navigatorStart
- 页面完全加载总时长:loadEventStart - navigationStart
- FP,首绘:可以通过performance.getEntriesByName(‘first-paint’)[0].startTime获得。
- FCP(First Contentful Paint)首次内容绘制:可以通过performance.getEntriesByName(‘first-contentful-paint’)[0].startTime获得。
有了以上这些东西,我们就可以自定义自己的测量标准,值得注意的是,获取性能参数,最好是在load之后。
附上页面的生命周期:
- readyState : loading 开始解析渲染 DOM 树
- readyState : interactive 完成DOM解析,准备加载内嵌资源
- DOMContentLoaded DOM 解析完成后,加载内嵌资源
- readyState : complete DOM树解析完成,并且资源也就绪
- onload 加载完成
- beforeunload 卸载页面之前
- unload 卸载页面