本文概述
- 旧基准
- 标准基准
- 使用浏览器基准
- 使用Performance.mark
测量Javascript代码的时间影响是识别热点的理想方法, 这是寻找如何提高脚本性能的第一步。
在本文中, 我们将向你展示3种方法来衡量脚本所花费的时间:
- 使用Date.getTime构建的基准。
- 使用Performance.now使用Javascript进行衡量的标准方法。
- 使用console.time和console.timeEnd的非标准方式。
- 使用performance.mark的非标准方式。
旧基准 过去, 你会使用诸如Date之类的东西来获取时间戳。 DOMTimeStamp返回整数毫秒数作为其值。这个成就还不错, 并且可以在所有浏览器中使用, 但是并不能提供很高的准确性。如果你使用Node.js, 则此解决方案会派上用场, 因为Node中没有可用的Performance对象, 因为没有DOM。
/** * Measure the time of execution with Date timestamp of a synchronous task * * @param {function} toMeasure * @param {int} repeatTimes * @return {Object} */function TimeBenchmark(toMeasure, repeatTimes){if(typeof(repeatTimes) != "number"){repeatTimes = 1;
}if(typeof(toMeasure) === "function"){var start_time = new Date().getTime();
for (var i = 0;
i <
repeatTimes;
++i) {toMeasure.call();
}var end_time = new Date().getTime();
}return {start:start_time, end: end_time, estimatedMilliseconds: end_time - start_time};
}
使用旧基准:
var TimesToBeExecuted = 10;
var TaskToBeExecuted = function(){// A task that you want to measure};
var TestResult = new TimeBenchmark(TaskToBeExecuted, TimesToBeExecuted);
console.log(TestResult);
标准基准 为了提供高分辨率时间所需的更高精度, 引入了一种称为DOMHighResTimeStamp(performance.now的返回值)的新类型。此类型是浮点值, 还返回以毫秒为单位的时间。但是, 由于它是浮点数, 所以该值可以表示毫秒数, 因此可以产生千分之一毫秒的精度。
该函数将根据X次执行来测量脚本的平均执行时间。这意味着你可以设置将重复执行此任务多少次, 并获取平均执行时间。请记住, 脚本的每次执行不一定都花费相同的时间(两者之间可能相差几毫秒), 因此你的任务将执行X次, 并且平均时间将与总花费的时间一起返回。
此函数依赖于performance.now函数, 并且可以在以下浏览器上运行:
- IE> = 10。
- 火狐> = 15。
- Chrome> = 24。
- Safari> = 8。
- 歌剧> = 15。
- Android> = 4.4
/** * Measure the time of execution in milliseconds of a synchronous task * * @param {function} toMeasure * @param {int} repeatTimes * @return {Object} */function StandardBenchmark(toMeasure, repeatTimes){if(typeof(repeatTimes) != "number"){repeatTimes = 1;
}if(typeof(toMeasure) === "function"){var start_status = performance.now();
var total_taken = 0;
for(var i = 0;
i <
repeatTimes;
i++){var startTimeSubtask = performance.now();
toMeasure.call();
var endTimeSubtask = performance.now();
total_taken += (endTimeSubtask -startTimeSubtask);
}var final_status = performance.now();
}return {totalMilliseconds: (final_status - start_status), averageMillisecondsPerTask: total_taken / repeatTimes};
}
使用StandardBenchmark:
var TimesToBeExecuted = 10;
var TaskToBeExecuted = function(){// A task that you want to measure};
var TestResult = new StandardBenchmark(TaskToBeExecuted, TimesToBeExecuted);
console.log(TestResult);
为了测试StandardBenchmark函数, 我们将使用jQuery和VanillaJS执行一个简单的DOM查询。该任务将被执行10000000(10M)次, 请参见下图:
文章图片
如你所见, 第一个基准测试使用jQuery, 执行大约需要113.9秒。每个查询平均每个查询0.01毫秒。另一方面, 第二个基准测试使用VanillaJS, 执行时间为17.5秒。大约比jQuery选择快6倍。
先前的基准测试是使用具有以下规格的笔记本电脑进行的:
- Windows 10家庭版64位版本-Chrome V 50.0.2661.102 m。
- Intel Core i5-4200U @ 1.60 GHz(4个CPU)。
- 4096 MB RAM。
- Windows 7 Ultimate 64位版本-Chrome V 50.0.2661.102 m。
- 英特尔酷睿i5-4590 @ 3.30 GHz
- 8192 MB内存
文章图片
使用jQuery, 每个查询的平均时间为0.001毫秒, 任务在12秒内完成。另一方面, 使用纯JavaScript的第二个基准测试需要执行3.5秒的时间, 而每个查询需要大约0.0002毫秒的时间才能完成。
使用浏览器基准 如果你需要在本地开发机器上获得函数执行时间, 则可以使用浏览器的配置工具:
文章图片
或控制台命令, 例如console.time()和console.timeEnd()。
console.time函数期望设置一个标识符, 然后将启动计时器并仅使用带有相应标识符的console.timeEnd(在控制台时间函数中先前设置)完成该计时器。给定页面上最多可以运行10000个计时器, 即:
var identifier = "SelectingAdomObject";
console.time(identifier);
// Start timer// Do somethingfor (var i = 0;
i <
10000000;
++i) {document.getElementById("myDomId");
}console.timeEnd(identifier);
// Stop timer and see result in the console
控制台中的结果应类似于:
文章图片
注意:console.time是非标准的, 不在标准轨道上, 因此请勿在生产环境中使用它。仅用于开发和测试目的。
以下函数包装console.time功能并执行X次任务。计时器将在循环外部设置, 并且只会确定执行X次任务所需的时间(不是每次都执行, 否则, 如果X次过高, 控制台将爆炸)。
function Benchmark(toMeasure, identifierName, repeatTimes){ if(!identifierName){ identifierName = new Date().getTime().toString();
}if(typeof(repeatTimes) != "number"){repeat = 1;
}if(typeof(toMeasure) === "function"){console.time(identifierName);
for(var i = 0;
i <
repeatTimes;
i++){toMeasure.call();
}console.timeEnd(identifierName);
return true;
}return false;
}
使用Performance.mark performance.mark方法是一个有用的时序分析工具包。用户计时API提供了一种方法, 你可以在Javascript的不同部分插入API调用, 然后提取详细的计时数据, 以帮助你进行优化。标记功能在浏览器内部存储时间戳。你可以使用自己想要的方式来命名时间戳, 该时间戳是一个单位。 performance.mark的使用非常简单:
performance.mark("StartMyLoop");
var myCounter = 0;
for(var i = 0;
i <
10000000;
i++){myCounter++;
document.getElementById("NonExistingDomElement");
}performance.mark("EndMyLoop");
这些方法将始终返回undefined。
现在, 如果要测量执行循环所花费的时间, 则应使用performance.measure, 此函数将标识符(随机名称)作为第一个参数, 将先前设置标记(开始标记)的名称作为第二个参数, 并将作为第三个参数, 前一个设置标记(结束标记)的名称。
var myMeasureId = "MyLoopTakeMilliseconds";
performance.measure(myMeasureId, "StartMyLoop", "EndMyLoop");
performance.measure方法非常有用, 因为你可以对许多标记执行比较, 而不仅限于所引用的标记(即Start1, End1, Start2, End2。你可以将Start1与End2等进行比较)。但是, 请注意, Performance.measure都不会返回任何东西。它将也返回未定义。要获取所有标记和测量值, 请使用getEntriesByType()方法, 即:
var marks = performance.getEntriesByType("mark");
var measurements = performance.getEntriesByType("measure");
console.log(marks, measurements);
StartMyLoop的结果将是(5748.075-2298.425 = 3449.6499)。看一下控制台:
文章图片
你可以分别使用以下方法丢弃之前的任何标记或尺寸:
performance.clearMarks('TheNameOfMyExistingMark');
performance.clearMeasures('TheNameOfMyExistingMeasurement');
【使用浏览器工具或创建自己的基准来使用JavaScript衡量功能的性能】在这里阅读更多有关用户计时API的信息, 祝你玩得开心。
推荐阅读
- 如何使用JavaScript将PDF转换为文本(从PDF提取文本)
- 如何在浏览器中使用JavaScript创建Gameboy Advance Emulator(GBA)
- Linux(内核剖析):09---进程调度之Linux调度的实现(struct sched_entityschedule())
- Linux(内核剖析):08---进程调度之Linux调度算法(调度器类公平调度(CFS))
- helm v3 在k8s 上面的部署skywalking
- 服务/软件管理(19---Linux与Windows之间Zmodem协议的开启与使用(rzsz命令))
- Linux(内核剖析):06---进程之线程的实现
- 服务/软件管理(17---Linux与Windows之间Samba服务的开启与使用)
- Linux(内核剖析):03---进程总体概述