几个月前, 我讲了一些HTML5 API ,这些API部分地侧重于如何衡量性能。 一种技术是通过高分辨率时间API,这是我的上一篇文章中描述的API。 该API允许您以毫秒级的分辨率来检索当前时间,而不受系统时钟偏差或调整的影响,这又使我们能够准确地测量JavaScript代码的性能。 尽管此API很有用,但使我们免于在代码中引入大量变量的痛苦。 另外,如果要测量在多个文件或模块中分割的代码的性能,则必须引入全局变量。 为了解决这些问题,我们可以使用用户计时API。
什么是用户计时API
User Timing API被定义为一个接口,可帮助Web开发人员通过访问高精度时间戳来评估其应用程序的性能。
换句话说,该API使您可以准确地测量和报告JavaScript代码的性能,这在需要对代码进行基准测试时非常理想。 作为 该API是W3C建议。 因此,规格是稳定的,几乎没有变化。
该API涉及两个主要概念:标记和度量。 第一个实现PerformanceMark
接口,第二个实现PerformanceMeasure
接口。 这两个接口都扩展了PerformanceEntry
接口 。 标记表示瞬间(时间戳),而小节表示两个标记之间经过的时间。 因为它们都扩展了PerformanceEntry
接口,所以它们拥有相同的四个只读属性:
-
name
:与标记或小节相关的助记符名称,用于检索它。 -
entryType
:指定对象的类型,即它是标记还是小节。 -
startTime
:如果对象是标记,则这是DOMHighResTimeStamp
,这是使用高分辨率时间API的performance.now()
方法检索的高精度时间戳。 如果对象是DOMHighResTimeStamp
,则它包含DOMHighResTimeStamp
开始标记的DOMHighResTimeStamp
。 -
duration
:如果对象是Mark,则该值始终为0(零)。 如果对象是小节,则它包含两个标记之间经过的时间。
该用户计时API公开了四个属于window.performance
对象的方法。 他们是:
-
mark(name)
:存储具有关联名称的DOMHighResTimeStamp
。 -
clearMarks([name])
:删除一个或所有存储的标记。 -
measure(name[, mark1[, mark2]])
:存储使用提供的名称的两个Mark之间经过的时间。 -
clearMeasures([name])
:删除一个或所有已存储的度量。
请注意,传递给mark()
和measure()
函数的名称不是唯一的ID。 您可以根据需要多次使用相同的名称。 在这种情况下,当您执行名称检索时,将返回按startTime
属性排序的数组。
在继续之前,让我们看一个简单的示例,该示例采用了所描述的一些方法。 假设我们要测量一个函数的执行时间,然后删除该测量而不显示数据。 执行此任务的代码如下所示:
performance.mark("startFoo");
// A time consuming function
foo();
performance.mark("endFoo");
performance.measure("durationFoo", "startFoo", "endFoo");
// Delete all Marks
performance.clearMarks();
// Delete the Measure "durationFoo"
performance.clearMeasure("durationFoo");
此代码段显示了如何调用前面介绍的所有方法。 但是,存储时间戳然后在不使用度量的情况下将其删除是完全没有用的。 要检索标记和度量的数据,我们需要使用属于Performance
接口的其他两种方法: getEntriesByType(type)
和getEntriesByName(name)
。 前者返回由type
参数指定的type
的实体列表(即Marks的“ mark”)。 后者返回名称由name
参数指定的实体的列表。 它们都返回基于startTime
属性排序的列表。
浏览器支持
在桌面和移动浏览器上,对该API的支持都不错。 此外,那些确实支持此API的应用程序不使用供应商前缀。 实现了用户计时API的台式机和移动浏览器是Internet Explorer 10 +,Chrome 25+和Opera 15+。 但是,由于Firefox在W3C推荐过程中的当前阶段,我们可以期望Firefox很快支持它。
“好的,但是如果我想在不支持该API的浏览器中使用该API怎么办?”
很高兴你问! 对我们来说幸运的是,有一个名为usertiming.js的polyfill允许我们使用前面描述的方法。 坏消息是此polyfill仅在支持High Time Time API及其performance.now()
方法的浏览器中起作用。
演示版
本部分提供了一个简单的演示,使您可以尝试本文中介绍的概念。 该演示定义了一个具有两个输入字段的简单表格。 在它们内部,我们有两个数字将用于模拟给定持续时间的耗时函数。 如果用户的浏览器不支持API,我们还将测试浏览器是否支持并显示“不支持API”消息。 如果浏览器支持User Timing API,我们将在表单内按钮的click
事件上附加一个侦听器。 单击后,我们将运行两个模拟函数并存储时间戳。 然后,我们测量经过的时间并显示一些存储的信息。 此处提供了以下代码的实时演示。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<meta name="author" content="Aurelio De Rosa">
<title>User Timing API Demo by Aurelio De Rosa</title>
<style>
body
{
max-width: 500px;
margin: 2em auto;
font-size: 20px;
}
h1
{
text-align: center;
}
.hidden
{
display: none;
}
.field-wrapper
{
margin-bottom: 1em;
}
.button-demo
{
padding: 0.5em;
display: block;
margin: 1em auto;
}
.author
{
display: block;
margin-top: 1em;
}
</style>
</head>
<body>
<h1>User Timing API</h1>
<form>
<div class="field-wrapper">
<label for="count-ut-1">Test 1: Count until</label>
<input type="number" id="count-ut-1" value="100000" />
</div>
<div class="field-wrapper">
<label for="count-ut-2">Test 2: Count until</label>
<input type="number" id="count-ut-2" value="1000000" />
</div>
<button type="button" id="button-play-ut" class="button-demo">Run demo</button>
</form>
<span id="ut-unsupported" class="hidden">API not supported</span>
<div id="ut-results" class="hidden">
<h2>Marks</h2>
<div id="ut-marks"></div>
<h2>Measures</h2>
<div id="ut-measures"></div>
</div>
<small class="author">
Demo created by <a href="http://www.audero.it">Aurelio De Rosa</a>
(<a href="https://twitter.com/AurelioDeRosa">@AurelioDeRosa</a>)
</small>
<script>
window.performance = window.performance || {};
if (performance.mark === undefined) {
document.getElementById('ut-unsupported').classList.remove('hidden');
document.getElementById('button-play-ut').setAttribute('disabled', 'disabled');
} else {
document.getElementById('button-play-ut').addEventListener('click', function() {
var i;
var perfMarks;
var perfMeasures;
document.getElementById('ut-results').classList.remove('hidden');
// A time consuming function
performance.mark("startTime1");
for(i = 0; i < parseInt(document.getElementById('count-ut-1').value); i++);
performance.mark("endTime1")
// Another time consuming function
performance.mark("startTime2");
for(i = 0; i < parseInt(document.getElementById('count-ut-2').value); i++);
performance.mark("endTime2");
performance.measure("durationTime1", "startTime1", "endTime1");
performance.measure("durationTime2", "startTime2", "endTime2");
performance.measure("durationTimeTotal", "startTime1", "endTime2");
// Print marks
perfMarks = performance.getEntriesByType("mark");
document.getElementById('ut-marks').innerHTML = '';
for (i = 0; i < perfMarks.length; i++) {
document.getElementById('ut-marks').innerHTML +=
"Name: " + perfMarks[i].name + " - " +
"Start Time: " + perfMarks[i].startTime + "<br />";
}
// Print measures
perfMeasures = performance.getEntriesByType("measure");
document.getElementById('ut-measures').innerHTML = '';
for (i = 0; i < perfMeasures.length; i++) {
document.getElementById('ut-measures').innerHTML +=
"Name: " + perfMeasures[i].name + " - " +
"Duration: " + perfMeasures[i].duration + "<br />";
}
performance.clearMarks();
performance.clearMeasures();
});
}
</script>
</body>
</html>
结论
本文探讨了User Timing API,并展示了它如何帮助您测试JavaScript代码的性能。 性能真的很重要,我们应该争取一点点的改进。
该API不会引入太多概念,因此您应该不难理解其属性和方法。 此外,它在浏览器中的支持非常好,因此您可以立即可靠地使用它。 但是,对于不支持User Timing API的用户(最著名的是Firefox),可以使用polyfill。
From: https://www.sitepoint.com/discovering-user-timing-api/