如何测量函数执行所需的时间

我需要获取执行时间(以毫秒为单位)。

我最初在 2008 年问这个问题。当时接受的答案是使用new Date()。getTime()。但是,我们现在都可以同意使用标准performance.now() API 更合适。因此,我正在改变对此的公认答案。

答案

使用performance.now()

var t0 = performance.now();

doSomething();   // <---- The function you're measuring time for 

var t1 = performance.now();
console.log("Call to doSomething took " + (t1 - t0) + " milliseconds.");

NodeJs :需要导入performance


使用console.time (非标准) 生活水平

console.time('someFunction');

someFunction(); // Whatever is timed goes between the two "console.time"

console.timeEnd('someFunction');

注意事项
传递给time()timeEnd()方法的字符串必须匹配
(以使计时器按预期完成)。

console.time()文档:

  1. 关于 NodeJS 的文档
  2. MDN(客户端)文档

使用新的 Date()。getTime()

getTime()方法返回自 1970 年 1 月 1 日午夜以来的毫秒数。

例如

var start = new Date().getTime();

for (i = 0; i < 50000; ++i) {
// do something
}

var end = new Date().getTime();
var time = end - start;
alert('Execution time: ' + time);

不要使用 Date()。参见下文。

使用performance.now()

<script>
var a = performance.now();
alert('do something...');
var b = performance.now();
alert('It took ' + (b - a) + ' ms.');
</script>

它适用于:

  • IE 10 ++

  • 火狐 15 ++

  • 铬 24 ++

  • Safari 8 ++

  • Opera 15 ++

  • Android 4.4 ++

  • 等等

console.time 对您来说可能是可行 ,但这是非标准的§

此功能是非标准的,不在标准轨道上。请勿在面向 Web 的生产站点上使用它:它不适用于每个用户。 实现之间可能存在很大的不兼容性,并且将来的行为可能会更改。

除了浏览器支持, performance.now似乎因为它似乎是的裸机版本,必须提供更准确的计时的潜力 console.time


另外, 永远不要将Date用于任何东西,因为它受 “系统时间” 更改的影响。这意味着当用户没有准确的系统时间时,我们得到无效的结果,例如 “负计时”:

2014 年 10 月,我的系统时钟转入混乱状态,开始猜测 ...。我打开 Gmail 并看到 “ 0 分钟前发送” 的当天所有电子邮件。而且我认为 Gmail 应该由 Google 的世界级工程师构建。

(将您的系统时钟设置为一年前,然后转到 Gmail,这样我们所有人都可以大笑。也许有一天,我们将为 JS Date带来一个耻辱大厅 。)

Google Spreadsheet 的now()函数也遭受此问题的困扰。

您唯一要使用Date是要向用户显示系统时钟时间。不是当你想要得到时间或测量任何东西。

如果需要在本地开发计算机上获得函数执行时间 ,则可以使用浏览器的概要分析工具,也可以使用控制台命令,例如console.time()console.timeEnd()

所有现代浏览器都内置了 JavaScript 分析器。这些分析器应该提供最准确的测量结果,因为您不必修改现有代码,这可能会影响函数的执行时间。

要分析您的 JavaScript,请执行以下操作:

  • Chrome 中 ,按F12并选择 “ 配置文件”标签,然后选择 “ 收集 JavaScript CPU 配置文件”
  • Firefox 中 ,安装 / 打开 Firebug,然后单击 “ 配置文件”按钮。
  • IE 9 + 中 ,按F12 ,单击 “ 脚本”或 “ 探查器” (取决于您的 IE 版本)。

另外,在开发机器上 ,您可以使用console.time()console.timeEnd()将检测添加到代码中。在 Firefox11 +,Chrome2 + 和 IE11 + 中受支持的这些功能会报告您通过console.time()启动 / 停止的计时器。 time()以用户定义的计时器名称作为参数,然后timeEnd()报告自计时器启动以来的执行时间:

function a() {
  console.time("mytimer");
  ... do stuff ...
  var dur = console.timeEnd("myTimer"); // NOTE: dur only works in FF
}

请注意,只有 Firefox 在timeEnd()调用中返回经过的时间。其他浏览器只是将结果报告给开发者控制台: timeEnd()的返回值是不确定的。

如果您想在野外获得函数执行时间 ,则必须对代码进行检测。您有两种选择。您可以通过查询new Date().getTime()来简单地保存开始时间和结束时间:

function a() {
  var start = new Date().getTime();
  ... do stuff ...
  var end = new Date().getTime();
  var dur = end - start;
}

但是, Date对象只有毫秒级的分辨率,并且会受到任何操作系统的系统时钟更改的影响。在现代浏览器中,有一个更好的选择。

更好的选择是使用高分辨率时间 ,也就是window.performance.now()now()在两个重要方面优于传统的Date.getTime()

  1. now()是具有毫秒级分辨率的 double,表示自页面导航开始以来的毫秒数。它以分数形式返回微秒数(例如,值 1000.123 为 1 秒和 123 微秒)。

  2. now()单调增加。这很重要,因为Date.getTime()在后续调用中可能会向前跳转甚至向后跳转。值得注意的是,如果操作系统的系统时间已更新(例如原子时钟同步),则Date.getTime()也将更新。 now()保证总是单调增加,因此它不受操作系统的系统时间的影响 - 它将始终是壁钟时间(假设壁钟不是原子钟...)。

now()几乎可以在new Date().getTime() + new Date Date.now()所在的每个位置使用。唯一的例外是Datenow()时间不混合,因为Date是基于unix-epoch (自 1970 年以来的毫秒数),而now()是自页面导航开始以来的毫秒数(因此它将比Date要小得多)。

这是如何使用now()的示例:

function a() {
  var start = window.performance.now();
   ... do stuff ...
  var end = window.performance.now();
  var dur = end - start;
}

Chrome 稳定版,Firefox 15 + 和 IE10 支持now() 。也有几种填充料

在野外测量执行时间的另一种选择是UserTiming 。 UserTiming 的行为与console.time()console.timeEnd()相似,但是它利用了now()使用的相同高分辨率时间戳(因此您获得了亚毫秒级的单调递增时钟),并将时间戳和持续时间保存到PerformanceTimeline

UserTiming 具有标记 (时间戳)和度量 (持续时间)的概念。您可以根据需要定义任意多个,并且它们在PerformanceTimeline上公开。

要保存时间戳,请调用mark(startMarkName) 。要获得自第一个标记以来的持续时间,只需调用measure(measurename, startMarkname) 。持续时间然后与标记一起保存在 PerformanceTimeline 中。

function a() {
  window.performance.mark("start");
  ... do stuff ...
  window.performance.measure("myfunctionduration", "start");
}

// duration is window.performance.getEntriesByName("myfunctionduration", "measure")[0];

在 IE10 + 和 Chrome25 + 中提供 UserTiming。还有一个polyfill可用(我写过)。

要获得精确的值,您应该使用Performance 接口 。 Firefox,Chrome,Opera 和 IE 的现代版本均支持该功能。这是一个如何使用它的示例:

var performance = window.performance;
var t0 = performance.now();
doWork();
var t1 = performance.now();
console.log("Call to doWork took " + (t1 - t0) + " milliseconds.")

Date.getTime()console.time()不适用于精确测量执行时间。如果可以快速进行粗略估算,则可以使用它们。粗略估计,我的意思是您可以从实时获得 15-60 毫秒的偏移。

查看有关如何用 JavaScript 测量执行时间的精彩文章 。作者还提供了一些有关 JavaScript 时间准确性的链接,值得阅读。

使用 Firebug,同时启用控制台和 Javascript。单击配置文件。重新加载。再次单击配置文件。查看报告。

process.hrtime()在Node.js 中可用 - 它返回一个以纳秒为单位的值

var hrTime = process.hrtime()
console.log(hrTime[0] * 1000000 + hrTime[1] / 1000)
var StopWatch = function (performance) {
    this.startTime = 0;
    this.stopTime = 0;
    this.running = false;
    this.performance = performance === false ? false : !!window.performance;
};

StopWatch.prototype.currentTime = function () {
    return this.performance ? window.performance.now() : new Date().getTime();
};

StopWatch.prototype.start = function () {
    this.startTime = this.currentTime();
    this.running = true;
};

StopWatch.prototype.stop = function () {
    this.stopTime = this.currentTime();
    this.running = false;
};

StopWatch.prototype.getElapsedMilliseconds = function () {
    if (this.running) {
        this.stopTime = this.currentTime();
    }

    return this.stopTime - this.startTime;
};

StopWatch.prototype.getElapsedSeconds = function () {
    return this.getElapsedMilliseconds() / 1000;
};

StopWatch.prototype.printElapsed = function (name) {
    var currentName = name || 'Elapsed:';

    console.log(currentName, '[' + this.getElapsedMilliseconds() + 'ms]', '[' + this.getElapsedSeconds() + 's]');
};

基准测试

var stopwatch = new StopWatch();
stopwatch.start();

for (var index = 0; index < 100; index++) {
    stopwatch.printElapsed('Instance[' + index + ']');
}

stopwatch.stop();

stopwatch.printElapsed();

输出量

Instance[0] [0ms] [0s]
Instance[1] [2.999999967869371ms] [0.002999999967869371s]
Instance[2] [2.999999967869371ms] [0.002999999967869371s]
/* ... */
Instance[99] [10.999999998603016ms] [0.010999999998603016s]
Elapsed: [10.999999998603016ms] [0.010999999998603016s]

performance.now()是可选的 - 只需将 false 传递给 StopWatch 构造函数即可。

您也可以在这里使用添加运算符

var start = +new Date();
 callYourFunctionHere();
 var end = +new Date();
 var time = end - start;
 console.log('total execution time = '+ time + 'ms');

为了进一步扩展 vsync 的代码以使其能够将 timeEnd 作为值返回到 NodeJS 中,请使用以下这段代码。

console.timeEndValue = function(label) { // Add console.timeEndValue, to add a return value
   var time = this._times[label];
   if (!time) {
     throw new Error('No such label: ' + label);
   }
   var duration = Date.now() - time;
   return duration;
};

现在使用如下代码:

console.time('someFunction timer');

someFunction();

var executionTime = console.timeEndValue('someFunction timer');
console.log("The execution time is " + executionTime);


这给您更多的可能性。您可以存储执行时间以用于更多目的,例如在方程式中使用它,或存储在数据库中,通过 websocket 发送到远程客户端,在网页上提供服务等。