使用浏览器工具或创建自己的基准来使用JavaScript衡量功能的性能

本文概述

  • 旧基准
  • 标准基准
  • 使用浏览器基准
  • 使用Performance.mark
?为什么要担心Javascript的性能?
测量Javascript代码的时间影响是识别热点的理想方法, 这是寻找如何提高脚本性能的第一步。
在本文中, 我们将向你展示3种方法来衡量脚本所花费的时间:
  • 使用Date.getTime构建的基准。
  • 使用Performance.now使用Javascript进行衡量的标准方法。
  • 使用console.time和console.timeEnd的非标准方式。
  • 使用performance.mark的非标准方式。
但是, 请记住, 在Firebug或Chrome Dev工具中使用性能分析通常是查找占用过多内存并保持浏览器挂起的代码的更好方法。
旧基准 过去, 你会使用诸如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)次, 请参见下图:
使用浏览器工具或创建自己的基准来使用JavaScript衡量功能的性能

文章图片
如你所见, 第一个基准测试使用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内存
得出以下结果:
使用浏览器工具或创建自己的基准来使用JavaScript衡量功能的性能

文章图片
使用jQuery, 每个查询的平均时间为0.001毫秒, 任务在12秒内完成。另一方面, 使用纯JavaScript的第二个基准测试需要执行3.5秒的时间, 而每个查询需要大约0.0002毫秒的时间才能完成。
使用浏览器基准 如果你需要在本地开发机器上获得函数执行时间, 则可以使用浏览器的配置工具:
使用浏览器工具或创建自己的基准来使用JavaScript衡量功能的性能

文章图片
或控制台命令, 例如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

控制台中的结果应类似于:
使用浏览器工具或创建自己的基准来使用JavaScript衡量功能的性能

文章图片
注意: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)。看一下控制台:
使用浏览器工具或创建自己的基准来使用JavaScript衡量功能的性能

文章图片
你可以分别使用以下方法丢弃之前的任何标记或尺寸:
performance.clearMarks('TheNameOfMyExistingMark'); performance.clearMeasures('TheNameOfMyExistingMeasurement');

【使用浏览器工具或创建自己的基准来使用JavaScript衡量功能的性能】在这里阅读更多有关用户计时API的信息, 祝你玩得开心。

    推荐阅读