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

我需要以毫秒为单位的执行时间。

我最初在2008年提出这个问题。当时接受的答案是使用#0。然而,我们现在都同意使用标准的#1 API更合适。因此,我将接受的答案改为这个。

1039926 次浏览

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

使用新日期. 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);

使用performance.now()

var startTime = performance.now()
doSomething()   // <---- measured code goes between startTime and endTime    
var endTime = performance.now()
console.log(`Call to doSomething took ${endTime - startTime} milliseconds`)

Node.js中,需要导入#1

进口性能

const { performance } = require('perf_hooks');

使用console.time:(生活水平

console.time('doSomething')    
doSomething()   // <---- The function you're measuring time for    
console.timeEnd('doSomething')

注:
传递给time()timeEnd()方法的字符串必须匹配
让计时器按预期完成)。

console.time()文件:

不要使用Date()。阅读下面的内容。

使用#0

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

它适用于:

  • ie10++

  • FireFox 15++

  • Chrome24++

  • Safari8++

  • Opera 15++

  • android 4.4++

  • 等等

console.time可能是可行的为你,但它是非标准的§

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

除了浏览器支持,performance.now似乎有潜在提供更准确的计时,因为它似乎是console.time的基本版本。


此外,永远不要将#0用于任何东西因为它受到“系统时间”变化的影响。这意味着当用户没有准确的系统时间时,我们会得到无效的结果-比如“负计时”:

2014年10月,我的系统时钟出了问题,猜怎么着……我打开Gmail,看到我一天中的第一封电子邮件“发送了0分钟前”。我以为Gmail应该是由谷歌的世界级工程师建造的…………………

(将您的系统时钟设置为一年前并转到Gmail,这样我们都可以开怀大笑。也许有一天我们会拥有JSDate耻辱大厅。)

Google电子表格的#0功能也存在这个问题。

您将使用Date的唯一时间是当您想向用户显示系统时钟时间时。不是当您想获取时间或测量任何东西时。

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

console.timeEndValue = function(label) { // Add console.timeEndValue, to add a return valuevar 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发送到远程客户端,在网页上提供服务等。

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构造函数。

如果您需要在本地开发机器上获得函数执行时间,您可以使用浏览器的分析工具或控制台命令,例如#0#1

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

要分析您的JavaScript:

  • Chrome中,按F12并选择个人资料选项卡,然后选择收集JavaScript CPU配置文件
  • Firefox中,安装/打开Firebug,然后单击简介按钮。
  • ie9+中,按F12,单击脚本分析器(取决于您的IE版本)。

或者,在您的开发机器上,您可以使用#0#1将检测添加到您的代码中。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()是一个具有亚毫秒分辨率的双精度值,表示自页面导航开始以来的毫秒数。它以小数形式返回微秒数(例如,1000.123的值为1秒,123微秒)。

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

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

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

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

now()在Chrome稳定,Firefox 15+和IE10中支持。还有几个PolyFill可用。

在野外测量执行时间的另一个选项是UserTiming. UserTiming的行为类似于console.time()console.timeEnd(),但它使用了now()使用的相同的高分辨率时间戳(因此您可以获得亚毫秒单调增加的时钟),并将时间戳和持续时间保存到业绩时间线

UserTiming有标志(时间戳)和措施(持续时间)的概念。您可以根据需要定义任意数量的时间戳,它们在业绩时间线上公开。

要保存时间戳,您可以调用mark(startMarkName)。要获取自您的第一个标记以来的持续时间,您只需调用measure(measurename, startMarkname)。然后,持续时间将与您的标记一起保存在表演时间轴中。

function a() {window.performance.mark("start");... do stuff ...window.performance.measure("myfunctionduration", "start");}
// duration is window.performance.getEntriesByName("myfunctionduration", "measure")[0];

UserTiming在IE10+和Chrome25+中可用。还有一个聚填充可用(我写的)。

如前所述,检查和使用内置计时器。但是,如果你想或需要写自己的,这里是我的两分钱:

//=-=|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字节gzip(405字节未压缩)
  • 编译大小:109字节gzip(187字节未压缩)
  • 节省50.23%的gzip大小(53.83%没有gzip

由于一些主要浏览器(即IE10)不支持console.timeperformance.now,我创建了一个利用最佳可用方法的超薄实用程序。然而,它缺乏对错误用法的错误处理(在未初始化的计时器上调用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);}}}

答案是错误

由于JavaScript是异步的,因此接受答案的变量end的值将是错误的。

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的执行可能非常快,所以你看不到结果是错误的。你可以使用执行一些请求的代码来测试它:

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

要获得精确的值,您应该使用性能接口。它在现代版本的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时间准确性的链接,值得一读。

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

let hrTime = process.hrtime()console.log(hrTime[0] * 1000000 + hrTime[1] / 1000)

谢谢,阿奇姆·科尔纳,将扩展你的答案:

var t0 = process.hrtime();//Start of code to measure
//End of codevar timeInMilliseconds = process.hrtime(t0)[1]/1000000; // dividing by 1000000 gives milliseconds from nanoseconds

请注意,除了要测量的内容之外,您不应该做任何事情(例如,console.log也需要时间来执行并会影响性能测试)。

请注意,为了按度量异步函数执行时间,您应该在回调中插入var timeInMilliseconds = process.hrtime(t0)[1]/1000000;。例如,

var t0 = process.hrtime();someAsyncFunction(function(err, results) {var timeInMilliseconds = process.hrtime(t0)[1]/1000000;
});

这是一个定时器功能。如果您想测量多个未嵌套的事物之间的时间:

function timer(lap){if(lap) console.log(`${lap} in: ${(performance.now()-timer.prev).toFixed(3)}ms`);timer.prev = performance.now();}

类似于console.time(),但如果您不需要跟踪以前的计时器,则更容易使用。


用法:

timer()              // set the start// do somethingtimer('built')       // logs 'built in: 591.815ms'// do somethingtimer('copied')      // logs 'copied in: 0.065ms'// do somethingtimer('compared')    // logs 'compared in: 36.41ms'

如果你喜欢console.time()中的蓝色,你可以用这条线代替

console.log(`${lap} in: %c${(performance.now()-timer.prev).toFixed(3)}ms`, 'color:blue');

它可以帮助你。

var t0=date.now();//做某事var t1=date.now();console.log(“Call to do的时间大约为”+(t1-t0)/1000+“秒”)

几个月前,我整理了自己的例程,使用Date.now () -- 乘以函数,即使当时接受的方法似乎是performance.now()--因为性能对象在稳定Node.js版本中还不可用(内置)。

今天我做了更多的研究,发现了另一种计时方法。因为我也发现了如何在Node.js代码中使用它,我想我会在这里分享它。

以下内容来自w3cNode.js给出的示例:

function functionTimer() {performance.mark('start')functionToBeTimed()performance.mark('end')performance.measure('Start to End', 'start', 'end')const measure = performance.getEntriesByName('Start to End')[0]console.log(measure.duration)}

注:

如果您打算在Node.js应用程序中使用performance对象,则必须包含以下要求:const{perf_hooks=

一个简单的解决方案,您也可以在此处使用添加运算符

 var start = +new Date();callYourFunctionHere();var end = +new Date();var time = end - start;console.log('total execution time = '+ time + 'ms');
export default class Singleton {
static myInstance: Singleton = null;
_timers: any = {};
/*** @returns {Singleton}*/static getInstance() {if (Singleton.myInstance == null) {Singleton.myInstance = new Singleton();}
return this.myInstance;}
initTime(label: string) {this._timers[label] = Date.now();return this._timers[label];}
endTime(label: string) {const endTime = Date.now();if (this._timers[label]) {const delta = endTime - this._timers[label];const finalTime = `${label}: ${delta}ms`;delete this._timers[label];return finalTime;} else {return null;}}}

string相关的InitTime。

return Singleton.getInstance().initTime(label); // Returns the time init

return Singleton.getInstance().endTime(label); // Returns the total time between init and end

这是一个定时函数装饰器

它包装函数,以便它们每次运行时都得到计时

用法:

let test = () => { /* does something */ }test = timed(test)   // turns the function into a timed function in one linetest()               // run your code as normal, logs 'function test took 1001.900ms'

这是装饰器:

let timed = (f) => (...args) => {let start = performance.now();let ret = f(...args);console.log(`function ${f.name} took ${(performance.now() - start).toFixed(3)}ms`);return ret;}

如果您使用的是异步函数,您可以将timed设置为异步并在f(… args)之前添加await,这应该适用于这些。如果您希望一个装饰器同时处理同步和异步函数,则会变得更加复杂。

在我的情况下,我更喜欢使用@语法suger并使用Babel编译它。
这个方法的问题是函数必须在对象内部。

JS代码示例

function timer() {return (target, propertyKey, descriptor) => {const start = Date.now();let oldFunc = descriptor.value;
descriptor.value = async function (){var result = await oldFunc.apply(this, arguments);console.log(Date.now() - start);return result;}}}
// Util functionfunction delay(timeout) {return new Promise((resolve) => setTimeout(() => {resolve();}, timeout));}
class Test {@timer()async test(timout) {await delay(timout)console.log("delay 1");await delay(timout)console.log("delay 2");}}
const t = new Test();t.test(1000)t.test(100)

. Babelrc(用于Babel 6)

 {"plugins": ["transform-decorators-legacy"]}

带累积周期的秒表

适用于服务器和客户端(Node或DOM),使用Performance API。当你有很多小周期时很好,例如在一个名为1000次的函数中,它处理1000个数据对象,但你想看看这个函数中的每个操作是如何加起来的。

所以这个使用了一个模块全局(单例)计时器。与类单例模式相同,只是使用起来简单一点,但您需要将其放在一个单独的例如stopwatch.js文件中。

const perf = typeof performance !== "undefined" ? performance : require('perf_hooks').performance;const DIGITS = 2;
let _timers = {};
const _log = (label, delta?) => {if (_timers[label]) {console.log(`${label}: ` + (delta ? `${delta.toFixed(DIGITS)} ms last, ` : '') +`${_timers[label].total.toFixed(DIGITS)} ms total, ${_timers[label].cycles} cycles`);}};
export const Stopwatch = {start(label) {const now = perf.now();if (_timers[label]) {if (!_timers[label].started) {_timers[label].started = now;}} else {_timers[label] = {started: now,total: 0,cycles: 0};}},/** Returns total elapsed milliseconds, or null if stopwatch doesn't exist. */stop(label, log = false) {const now = perf.now();if (_timers[label]) {let delta;if(_timers[label].started) {delta = now - _timers[label].started;_timers[label].started = null;_timers[label].total += delta;_timers[label].cycles++;}log && _log(label, delta);return _timers[label].total;} else {return null;}},/** Logs total time */log: _log,delete(label) {delete _timers[label];}};

只能使用一个变量:

var timer = -performance.now();
// Do something
timer += performance.now();console.log("Time: " + (timer/1000).toFixed(5) + " sec.")

timer/1000-将毫秒转换为秒

.toFixed(5)-修剪多余的数字

有多种方法可以实现这一目标:

  1. 使用console.time

    console.time('function');//run the function in between these two lines for that you need to//measure time taken by the function. ("ex. function();")console.timeEnd('function');
  2. this is the most efficient way :using performance.now(), e.g.

    var v1 = performance.now();//run the function here for which you have top measure the timevar v2 = performance.now();console.log("total time  taken = "+(v2-v1)+"milliseconds");
  3. use +(add operator) or getTime()

    var h2 = +new Date(); //orvar h2 = new Date().getTime();for(i=0;i<500;i++) { /* do something */}var h3 = +new Date();   //orvar h3 = new Date().getTime();var timeTaken = h3-h2;console.log("time ====", timeTaken);

Here's what happens when you apply the unary plus operator to a Date instance:Get the value of the Date instance in questionConvert it to a Number

NOTE: getTime() gives better performance than unary + operator.

最好的方法是使用performance hooks模块。虽然不稳定,但您可以mark代码的特定区域,measure标记区域之间的duration

const { performance, PerformanceObserver } = require('perf_hooks');
const measures = []
const obs = new PerformanceObserver(list => measures.push(...list.getEntries()));obs.observe({ entryTypes: ['measure'] });const getEntriesByType = cb => cb(measures);
const doSomething = val => {performance.mark('beginning of the process');
val *= 2;
performance.mark('after multiplication');
performance.measure('time taken', 'beginning of the process', 'after multiplication');
getEntriesByType(entries => {entries.forEach(entry => console.log(entry));})
return val;}
doSomething(4);

尝试这里

与性能

NodeJs:需要导入性能类

var time0 = performance.now(); // Store the time at this point into time0
yourFunction();   // The function you're measuring time for
var time1 = performance.now(); // Store the time at this point into time1
console.log("youFunction took " + (time1 - time0) + " milliseconds to execute");

使用console.time

console.time('someFunction');
someFunction(); // Whatever is timed goes between the two "console.time"
console.timeEnd('someFunction');
  1. 开始定时器使用console.time("myTimer");
  2. 可选:对于打印经过的时间,使用console.timeLog("myTimer");
  3. 最后,停止定时器并打印进入决赛time:console.timeEnd("myTimer");

你可以在MDNNode.js留档中阅读更多关于这一点的信息。

可在Chrome、Firefox、Opera和NodeJS上使用(不在Edge或Internet Explorer上)。

在函数之前使用console.time('some label here'),在函数之后使用console.timeEnd('some label here')。它会给你函数的运行时间。

使用此代码格式

const startTime =new Date().getTime();
//do somethingconst endTime = new Date().getTime();console.log(`time taken ${(endTime - startTime)/1000} seconds`);

支持标记的基本TypeScript示例。调用start('something')将开始计时器,stop('something')将结束计时器并返回包含经过时间的格式化字符串。

查看Flems示例

/*** Mark entries*/export const marks: { [id: string]: number } = {};
/*** Start timing*/export const start = (id: string) => {return Object.assign(marks, {[id]: Date.now() })[id]}
/*** Clear all*/export const clear = () => {for (const id in marks) delete marks[id];};
/*** Stop timing and return formatted elapsed time*/export const stop = (id: string) => {const ms = Date.now() - marks[id];delete marks[id];return ms > 1000? `${(ms / 1000).toFixed(0)}s ${+ms.toFixed(0).slice(1)}ms`: `${ms.toFixed(0)}ms`;};

示例代码正在导出每个函数。你可以将其放入项目中,并从默认的as导入相应地调用方法,例如:

import * as time from './timer.js'
time.start('foo')
// do something
console.log('elapsed time: ' + time.stop('bar'))

注意:最简单的纯函数式实现,ES6方法,不需要额外的变量,只需3行代码。处理同步和异步代码,因此不需要外部库,适用于JavaScript和Node JS,甚至可以用来测试API的延迟

    // Create one-liner timer functionlet [timer, timingMonitor] = [0, () => timer = !timer ? Date.now() : `${Date.now() - timer}ms`]    
// Initiate timertimingMonitor();    
// Your code heredoSomething();    
// Capture and store the End timerconst timeElapsed = timingMonitor();
console.log(timeElapsed);// Console output: "102ms", for example