如何测量一个函数执行所花费的时间
我需要以毫秒为单位获得执行时间。
我最初在2008年问过这个问题。接受的答案是使用新的Date()。getTime()但是,现在我们都可以同意使用标准的performance.now() API更合适。 因此,我正在改变这个问题的答案。
你可以使用console.time 🙁 非标准的)
console.time('someFunction'); someFunction(); // run whatever needs to be timed in between the statements console.timeEnd('someFunction');
注意 :
传递给time()
和timeEnd()
方法的string必须匹配
( 定时器按预期完成)。
更新
您可以使用标准的performance.now() API,如下所示:
var t0 = performance.now(); doSomething(); var t1 = performance.now(); console.log("Call to doSomething took " + (t1 - t0) + " milliseconds.")
使用新的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 ++
-
Chrome 24 ++
-
Safari 8 ++
-
Opera 15 ++
-
Android 4.4 ++
-
等等
console.time
可能适合你 ,但它是非标准的§ :
这个function是非标准的,不在标准轨道上。 不要在面向Web的生产站点上使用它:它不适用于每个用户。 实现之间也可能存在大的不兼容性,并且行为在未来可能会改变。
除了浏览器支持, performance.now
似乎有可能提供更准确的计时,因为它似乎是console.time
版本。
另外, 不要使用Date
来做任何事情,因为它受到“系统时间”变化的影响。 这意味着我们将得到无效的结果 – 如“否定时间” – 当用户没有准确的系统时间时:
在2014年10月,我的系统时钟出现故障, 猜测是什么 ….我打开了Gmail,看到我的一天的电子邮件“ 0分钟前发送”。 我以为Gmail应该由来自Google的世界级工程师构build
(把你的系统时钟设置为一年前,然后进入Gmail,这样我们都可以大笑一场,也许有一天我们会有一个JS Date
的耻辱堂 。)
Google Spreadsheet的now()
函数也会遇到这个问题。
唯一的一次你将使用Date
是当你想显示用户他的系统时钟的时间。 不是当你想得到时间或测量任何东西。
如果您需要在本地开发机器上获取函数执行时间 ,则可以使用浏览器的分析工具或控制台命令(如console.time()
和console.timeEnd()
。
所有现代浏览器都内置有JavaScript分析器。 这些分析器应该提供最准确的测量,因为您不必修改现有的代码,这可能会影响函数的执行时间。
要分析您的JavaScript:
- 在Chrome中 ,按F12 ,然后selectconfiguration文件选项卡,然后select收集JavaScript CPUconfiguration文件 。
- 在Firefox中 ,安装/打开Firebug,然后点击configuration文件button。
- 在IE 9+中 ,按F12 ,点击Script或Profiler (取决于你的IE版本)。
或者,在您的开发机器上 ,您可以使用console.time()
和console.timeEnd()
将代码添加到代码中。 Firefox11 +,Chrome2 +和IE11 +支持这些function,通过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()
的返回值是未定义的。
如果你想获得function执行时间 ,你将不得不使用你的代码。 你有几个选项。 您可以通过查询new Date().getTime()
来简单地保存开始和结束时间new Date().getTime()
:
function a() { var start = new Date().getTime(); ... do stuff ... var end = new Date().getTime(); var dur = end - start; }
但是, Date
对象只有毫秒的分辨率,并会受到任何操作系统的系统时钟变化的影响。 在现代浏览器中,有一个更好的select。
更好的select是使用高分辨率时间 ,也就是window.performance.now()
。 now()
比传统的Date.getTime()
有两个重要的好处:
-
now()
是一个具有亚毫秒分辨率的双精度值,表示从页面导航开始以来的毫秒数。 它返回分数中的微秒数(例如,1000.123的值是1秒和123微秒)。 -
now()
是单调递增的。 这很重要,因为Date.getTime()
可能会在后续调用中向前或向后跳转。 值得注意的是,如果操作系统的系统时间被更新(例如primefaces钟同步),Date.getTime()
也会被更新。now()
保证总是单调递增,所以它不受操作系统系统时间的影响 – 它总是挂钟时间(假设你的挂钟不是primefaces的)。
now()
几乎可以用在每个new Date().getTime()
, + new Date
Date.now()
都是的地方。 Date
和now()
时间是不能混合的,因为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()
。 也有几个polyfills可用。
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];
UserTiming可在IE10 +和Chrome25 +中使用。 还有一个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。 点击个人资料 刷新。 再次点击个人资料 查看报告。
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的构造函数即可。
process.hrtime()在Node.js中可用 – 它返回一个以毫微秒为单位的值
var hrTime = process.hrtime() console.log(hrTime[0] * 1000000 + hrTime[1] / 1000)
要进一步扩展vsync的代码以便能够将时间结束作为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);
这给你更多的可能性。 您可以将执行时间存储为用于更多目的,如在公式中使用它,或存储在数据库中,通过websockets发送到远程客户端,在网页上提供等。
谢谢,Achim Koellner,将会扩大你的答案:
var t0 = process.hrtime(); //Start of code to measure //End of code var timeInMilliseconds = process.hrtime(t0)[1]/1000000; // dividing by 1000000 gives milliseconds from nanoseconds
请注意,你不应该做任何你想测量的东西(例如, console.log
也需要一些时间来执行,并会影响性能testing)。
注意,为了通过度量asynchronous函数的执行时间,你应该插入var timeInMilliseconds = process.hrtime(t0)[1]/1000000;
在callback里面。 例如,
var t0 = process.hrtime(); someAsyncFunction(function(err, results) { var timeInMilliseconds = process.hrtime(t0)[1]/1000000; });
由于console.time
和performance.now
在一些主stream浏览器(ie IE10)中不被支持,我创build了一个利用最好的可用方法的超薄实用程序。 但是,它缺lesserror handling的error handlingEnd()
在未初始化的定时器上调用End()
)。
使用它并根据需要进行改进。
Performance: { Timer: {}, Start: function (name) { if (console && console.time) { console.time(name); } else if (window.performance.now) { this.Timer[name] = window.performance.now(); } else { this.Timer[name] = new Date().getTime(); } }, End: function (name) { if (console && console.time) { console.timeEnd(name); } else { var result; if (window.performance.now) { result = window.performance.now() - this.Timer[name]; } else { result = new Date().getTime() - this.Timer[name]; } console.log(name + ": " + result); } } }
如果你想测量多个不嵌套的东西之间的时间,你可以使用这个:
function timer(lap){ if(lap) console.log(lap, 'in:', (performance.now()-timer.prev).toFixed(3) + 'ms'); timer.prev = performance.now(); }
// Usage: timer() // set the start //... timer('built') //... timer('copied') //... timer('compared') /* Output would look like this: built in: 591.815ms copied in: 0.065ms compared in: 36.41ms */
与console.time()
类似,但如果不需要跟踪以前的定时器, console.time()
容易使用。
如果您喜欢console.time()
的蓝色,您可以使用此行代替上面的代码获得相同的效果
console.log(lap +' in: %c'+(performance.now()-timer.prev).toFixed(3) +'ms', 'color:blue');
如前所述检查并使用内置定时器。 但是如果你想要或者需要在这里写自己是我的两分钱:
//=-=|Source|=-=// /** * JavaScript Timer Object * * var now=timer['elapsed'](); * timer['stop'](); * timer['start'](); * timer['reset'](); * * @expose * @method timer * @return {number} */ timer=function(){ var a=Date.now(); b=0; return{ /** @expose */ elapsed:function(){return b=Date.now()-a}, start:function(){return a=Date.now()}, stop:function(){return Date.now()}, reset:function(){return a=0} } }(); //=-=|Google Advanced Optimized|=-=// timer=function(){var a=Date.now();b=0;return{a:function(){return b=Date.now()-a},start:function(){return a=Date.now()},stop:function(){return Date.now()},reset:function(){return a=0}}}();
汇编是成功的!
- 原始大小:219个字节gzipped(405个字节未压缩)
- 编译大小:109个字节gzipped(187个字节未压缩)
- gzip尺寸(53.83%,不含gzip),节省了50.23%
接受的答案是错的 !
由于JavaScript是asynchronous的,被接受的答案的variables结束的值是错误的。
var start = new Date().getTime(); for (i = 0; i < 50000; ++i) { // JavaScript is not waiting until the for is finished !! } var end = new Date().getTime(); var time = end - start; alert('Execution time: ' + time);
for的执行可能非常快,所以你看不到结果是错误的。 你可以用一个请求来testing它:
var start = new Date().getTime(); for (i = 0; i < 50000; ++i) { $.ajax({ url: 'www.oneOfYourWebsites.com', success: function(){ console.log("success"); } }); } var end = new Date().getTime(); var time = end - start; alert('Execution time: ' + time);
所以警报将很快提示,但在控制台中,您将看到ajax请求正在继续。
下面是你应该怎么做: https : //developer.mozilla.org/en-US/docs/Web/API/Performance.now