web性能优化监控分析神器【Web Performance Timing API】


Web Performance Timing API


简介


想象一下您正在访问咱们的W3C网站,若是Web内容在必定时间内没有显示在屏幕上,那么做为用户,也许您只是关闭选项卡,而后转到其余选项。可是,做为开发人员,您可能但愿跟踪请求和导航详细信息中的提示,以便找出致使此网页速度降低的缘由。javascript

幸运的是,大多数浏览器供应商都愿意公开容许开发人员收集准确性能细节的性能特征。顾名思义,这些性能计时API有助于从不一样方面识别Web应用程序的瓶颈并提升性能。css





当试图了解Web应用程序的性能时,瀑布图多是您会想到的第一个工具。您是否想过了解这些图形图表背后的魔力?在如下各节中,咱们将解释一组性能监视API,这些API使您不只能够执行瀑布图测量。html

资源时效【Resource Timing】

上图是一个简单网页每一个加载资源的时间数据的瀑布图。实际上,[RESOURCE-TIMING]  API 能够提供比这更多的详细信息。图2是开发人员可以访问的 Web 应用程序中每一个加载资源的一组属性。前端





资源的加载时间【Load Times for Resources 】

Web 应用程序大多由一组可下载的资源组成。这里的资源一般引用 HTML 文档、 XHR 对象、连接(例如样式表)或 SVG 元素。java

Resources Timing 数据做为全局 window.performance 对象上的方法公开,咱们将在下一节讨论这个问题。建议您使用 performance.getEntriesByType("Resource")方法为每一个请求的资源获取一个资源计时对象数组。web





Performanceresourcetiming 接口扩展了 Performance Timeline 中的 PerformanceEntry 接口。资源计时中的属性能够用 responseEndstartTime 之间的差值来计算所用的时间。面试

如图2和图3所示,您能够访问页面上每一个资源的一组关键网络计时属性。算法

每一个时间戳都以微秒为单位,由 High Resolution Time 规范中的 window.performance.now()方法提供。shell

例子【Example】

举个例子,让咱们来测量一下获取 W3C 主页上的图标所需的时间。api

<!doctype html><html> <head> </head> <body onload="loadResources()"> <script> function loadResources(){ var image1 = new Image(); image1.onload = resourceTiming; image1.src = 'https://www.w3.org/Icons/w3c_main.png'; }
function resourceTiming(){ var resourceList = window.performance.getEntriesByType("resource"); for (var i = 0; i < resourceList.length; i++) { if (resourceList[i].initiatorType == "img") { alert("End to end resource fetch: " + (resourceList[i].responseEnd - resourceList[i].startTime)); } } }</script> <img id="image0" src="https://www.w3.org/Icons/w3c_home.png"> </body></html>

浏览器兼容【Browser Support】

到目前为止,[RESOURCE-TIMING] API 已获得普遍实现。图4显示了主要的桌面和移动网络浏览器的当前支持数据,请访问 caniuse.com 了解最新状态。





执行时间线【Performance Timeline】

概要【Overview】

您可能已经开始思考,这些网页上资源的计时数据是否足够好,以衡量其性能?是的,为了理解你的 web 应用程序,老是有必要探索更多: 页面导航、用户交互、请求-响应循环等。根据这一要求,Web 性能工做组引入了性能时间表,这是一个统一的接口,用于获取各类性能指标。

EntryTypePerformance Timeline API 使用 PerformanceEntry.entryType 来描述这个 PerformanceEntry对象所表示的接口类型,它表示测算的性能(时间)。var entryType = performance.getEntries()[0].entryType// Entry Type

每一个 PerformanceEntry 对象都公开如下继承的属性:

performance.getEntries

performance.getEntries用来获取当前时间调用前,浏览器从进入该页面开始的全部事件类型的详细时间数据,返回是一个Array<PerformanceEntry>

name(名称)

这个属性的 DOMString 标识符对象,不必定是惟一的。

entryType(类型)

描述由此表示DOMString接口类型的 PerformanceEntry对象。

startTime(开始时间)

此性能指标的第一个记录时间戳的时间值。

duration(所用时间)

此记录的整个事件持续时间的时间值

W3c WebPerf WG 维护 PerformanceEntry.entryType 的已知值列表。

entryType 的值

分析较长的用时【High-Resolution Time】

前言【Introduction】

参与 Performance Timeline 的全部指标都可以以亚毫秒级的分辨率提供计时数据,即 DOMHighResTimeStamp,它由高分辨率时间规范[ HR-TIME-2]定义。

单调计时【Monotonic Clock】

在设计的早期阶段,咱们的计时 api 是根据墙上时钟的时间来定义的。不幸的是,在现代计算机系统中,这样的时间有一个使人不快的特性: 它们并非以时间实际流逝的速度单调地增加。特别是,NTP 调整、用户配置更改等等会致使系统报告的时间向后、向前太快或向前太慢。

例如,能够在到 Date.now()的两个调用之间登陆正数、负数或零。

var mark_start = Date.now();doTask(); // Some taskif (window.console) window.console.log('Duration of task: ' + (Date.now() - mark_start));

High-Resolution Time的概念是提供一个单调的、均匀递增的时间戳,适用于区间测量,这是基于如下规则而实现的:

  • now()方法时返回的时间值和Performance 方法,工做表现对象具备相同时间起源【time origin】 必须不受系统时钟调整或系统时钟偏斜的影响。

  • now()方法返回的任意两个按时间顺序记录的时间值之间的差值,若是两个时间值具备相同的值,则永远不要为负数

亚毫秒分析【Sub-millisecond Resolution】

Now()在肯定日历时间的当前值方面确实很是有用,并且使用历史悠久。然而,从长远来看,须要更高的精确度。

图形就是一个例子。在计算基于脚本的动画的帧速率时,开发人员须要亚毫秒的分辨率来肯定一个动画是否在60 FPS 下绘制。若是没有亚毫秒级的分辨率,开发人员只能肯定动画是以58.8 FPS 仍是62.5 FPS 绘制。

Domhighrestimestamp 类型和 Performance 接口的now()方法经过提供亚毫秒级分辨率的时间值来解决本节中总结的问题。

时间起源【Time Origin】

时间起源肯定时间值从哪一个时间被测量。对于专用工做线程或文档,起始时间是该文档页面导航的开始时间,对于共享工做线程,起始时间是建立共享工做线程的时间。为了更准确的定义,请检查规范的细节。

假设咱们有一个共享工做线程 a,它是在父文档的导航开始后10ms 建立的。若是在工做线程和父上下文中建立共享工做线程 a 以后,咱们称之为 performance.now() 要用时5ms,那么咱们应该看到如下值:

Shared worker A:performance.now(): 5.000 ms
Parent context:performance.now(): 15.000 ms


要在相同的时间线上显示这样的事件,应用程序可使用 translateTime 方法从工做线上转换 DOMHighResTimeStamps

// ---- worker.js -----------------------------// Shared worker scriptonconnect = function(e) { var port = e.ports[0]; port.onmessage = function(e) { // Time execution in worker var task_start = performance.now(); result = runSomeWorkerTask(); var task_end = performance.now();
port.postMessage({ 'task': 'Some worker task', 'start_time': task_start, 'end_time': task_end, 'result': result }); }}
// ---- application.js ------------------------// Timing tasks in the documentvar task_start = performance.now();result = runSomeWorkerTask();var task_end = performance.now();
plotEventOnTimeline({ 'task': 'Some document task', 'start_time': task_start, 'end_time': task_end, 'result': result});
// Translating worker timestamps into document's time originvar worker = new SharedWorker('worker.js');worker.port.onmessage = function (event) { var msg = event.data;
// translate timestamps into document's time origin msg.start_time = performance.translateTime(msg.start_time, worker); msg.end_time = performance.translateTime(msg.end_time, worker);
// plot the results on document's timeline plotEventOnTimeline(msg);}
 

originTime 添加到 performance.now()中,就会获得一个在任何上下文中均可以比较的时间值。如今咱们能够获得这样的结果:

Shared worker A:performance.now(): 5.000 msperformance.originTime: 110.000 msperformance.originTime + performance.now(): 115.000 ms
Parent context:performance.now(): 15.000 msperformance.originTime: 100.000 msperformance.originTime + performance.now(): 115.000 ms


导航时间【Navigation Timing】

如今咱们知道了如何获取单个资源的计时指标,接下来让咱们进一步访问文档导航的完整计时信息。

导航时间、性能时间线和资源时间【Navigation Timing, Performance Timeline and Resource Timing】

导航是关于用户代理如何将请求的 HTMLCSSJavaScript 转换为渲染的像素,这是用户浏览文档最关键的步骤之一。


导航计时 API 是 Web 性能 API 的起点。在[ NAVIGATION-TIMING ]中,经过访问 window.performance.navigation,您将得到一个 PerformanceNavigationTiming 实例,该实例提供有关页面性能的与时间相关的信息。这不符合经过performance.getEntries 提供统一入口的目标。到2011年引入性能时间轴 api 时,导航计时的初始设计已经被普遍实现,所以要将其与性能时间轴对齐为时已晚。


导航计时 API Level 2试图经过一个理想的导航计时设计来修复这个历史性的错误。它参与 Performance Timeline API,并从 PerformanceResourceTiming 接口扩展 initialatortypeworkerStart

PerformanceNavigationTiming 的属性

图5显示了在[ NAVIGATION-TIMING-2]中定义的页面的导航的关键性能特征列表。





下面是浏览 www.w3.org 网页的演示。





浏览器兼容【Browser Support】

图7是由 caniuse 网站生成的支持数据表[ NAVIGATION-TIMING]。





用户时间【User Timing】

到目前为止,经过导航时序和资源时序,您能够充分访问资源加载和页面导航中那些关键时刻的时序信息。可是,若是您想肯定用户的按钮点击交互出了什么问题,该怎么办?是否有可能得到对你来讲很重要的我的任务的高精度性能特征?

User TimingPerformance 接口的扩展,能够经过提供高精度的时间戳帮助您度量应用程序的性能。

这里有一个简单的示例,解释了开发人员如何使用本文中定义的接口来获取与开发人员脚本相关的计时数据。

<!doctype html><html> <head> <title>User Timing example</title> </head> <body onload="init()"> <script> function init(){ performance.mark("startTask1"); doTask1(); // Some developer code performance.mark("endTask1");
performance.mark("startTask2"); doTask2(); // Some developer code performance.mark("endTask2");
measurePerf(); }
function measurePerf(){ var perfEntries = performance.getEntriesByType("mark"); for (var i = 0; i < perfEntries.length; i++) { if (window.console) console.log("Name: " + perfEntries[i].name + " Entry Type: " + perfEntries[i].entryType + " Start Time: " + perfEntries[i].startTime + " Duration: " + perfEntries[i].duration + "\n"); } }</script> </body></html>


手动打点【performance.mark()】

Performancemark 接口扩展了 Performance 接口,并经过一个名为 mark()的函数向用户公开标记。

Mark()容许 web 开发人员在他们的 web 应用程序中建立独特的标记,并使用 DOMString markName 自定义标记。例如,要建立一个名为before click 的标记,请调用 window.performance.mark("before click”) ;

您可使用 Performance 接口访问已经存储的标记。经过调用 window.performance.getEntriesByType(" mark") ,您将获得应用程序中全部标记的列表。

当标记再也不具备任何价值时,能够删除它们。您能够经过调用 clearMarks()来删除全部的标记,或者经过调用 clearMarks("mark to delete")来删除一个标记、标记要删除。

计算点之间的耗时【performance.measure()】

当您准备了足够的标记(两个点+)时,PerformanceMeasure 接口能够帮助您计算两个标记之间的运行时间。此接口也是 Performance 接口的扩展,该接口公开经过 measure()方法建立的度量。在这里,measure ()存储两个标记之间的 DOMHighResTimeStamp 持续时间以及相关的名称("measure")。例如,要度量连续的单击,咱们能够调用 window.performance.measure("measure click","click before","click after")

PerformanceMark 接口相似,只需调用 window.performance.getEntriesByType("measure")就能够得到度量值,并使用 clearMeasures()方法删除度量值。

浏览器兼容【Browser Support】

如今,你能够在大多数主流浏览器上使用 User Timing API。请访问 caniuse 网站获取最新的浏览器支持信息。





应用场景

  • 检测 WEB 应用的各依赖资源的加载时间,并上报到服务器进行分析

  • 对耗时可能较长的方法函数进行耗时监听,并上传服务器进行分析

  • 分析用户从进入网页开始到页面呈现的全部时间,而且上传服务器分析首屏渲染耗时

当拿到上述的数据后,咱们就能够对数据进行分析,知道咱们的程序到底慢在哪里,而后作正对性的优化,而不像原来没有数据的支撑致使咱们无从下手优化工做。

以上是我对英版原版文档的翻译,若是有翻译不对的地方还请谅解。

2020年4月1日

Jboss(基老板)


做者:JBoss连接:https://juejin.im/post/5e849e6de51d4546e14f4304

感谢阅读❤️

欢迎关注「前端瓶子君」,回复「交流」加入前端交流群!

欢迎关注「前端瓶子君」,回复「算法」自动加入,从0到1构建完整的数据结构与算法体系!

在这里,瓶子君不只介绍算法,还将算法与前端各个领域进行结合,包括浏览器、HTTP、V八、React、Vue源码等。

在这里,你能够天天学习一道大厂算法题(阿里、腾讯、百度、字节等等)或 leetcode,瓶子君都会在次日解答哟!

》》面试官也在看的算法资料《《

“在看转发”是最大的支持

本文分享自微信公众号 - 前端瓶子君(pinzi_com)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。

相关文章
相关标签/搜索