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

时间:2008-11-24 11:09:14

标签: javascript profiling

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

  

我最初在2008年问过这个问题。接受了答案   那就是使用new Date().getTime()但是,我们现在都同意了   使用标准performance.now() API更多   适当。因此,我正在改变对此人的接受答案。

30 个答案:

答案 0 :(得分:1411)

使用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 :需要import the performance课程


使用 console.time (非标准) living standard

console.time('someFunction');

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

console.timeEnd('someFunction');

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

  

console.time()文件:

     
      
  1. NodeJS documentation regarding
  2.   
  3. MDN (client-side) documentation
  4.   

答案 1 :(得分:603)

使用new 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);

答案 2 :(得分:389)

不要使用Date()。请阅读以下内容。

使用performance.now()

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

适用于:

  • IE 10 ++

  • FireFox 15 ++

  • Chrome 24 ++

  • Safari 8 ++

  • Opera 15 ++

  • Android 4.4 ++

  • etc, etc

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

  

此功能不符合标准,不符合标准。不要在面向Web的生产站点上使用它:它不适用于每个用户。 也可能是实现之间存在很大的不兼容性,并且行为可能在将来发生变化。

除了浏览器支持之外,performance.now似乎还有潜力来提供更准确的时间安排,因为它似乎是console.time的简单版本。


&LT;咆哮&GT;此外,不要将Date用于任何 ,因为它受“系统时间”更改的影响。这意味着当用户没有准确的系统时间时,获得无效结果 - 如“负时间”:

  

2014年10月,我的系统时钟乱了,猜猜是什么 ....我打开了Gmail,看到我当天所有的电子邮件“发送 0分钟前”。我认为Gmail应该由来自Google的世界级工程师构建.......

(将您的系统时钟设置为一年前,然后转到Gmail,这样我们就可以大笑。也许有一天我们会为JS Date提供Hall of Shame。)

Google电子表格的now()功能也会遇到此问题。

您要使用Date的唯一时间是您希望向用户显示他的系统时钟时间。不是在您想要获得the time或测量任何内容时。

答案 3 :(得分:50)

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

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

分析您的JavaScript:

  • Chrome 中,按 F12 并选择配置文件标签,然后收集JavaScript CPU配置文件
  • Firefox 中,安装/打开Firebug,然后单击配置文件按钮。
  • IE 9 + 中,按 F12 ,点击脚本 Profiler (具体取决于您的版本) 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对象只有毫秒级的分辨率,并且会受到任何操作系统时钟更改的影响。在现代浏览器中,有一个更好的选择。

更好的选择是使用High Resolution Time,即window.performance.now()now()在两个重要方面优于传统Date.getTime()

  1. now()是一个亚毫秒分辨率的双精度,表示自页面导航开始以来的毫秒数。它返回小数中的微秒数(例如,1000.123的值是1秒和123微秒)。

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

  3. now()几乎可用于new Date().getTime()+ new DateDate.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 stable,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];
    

    用户定时适用于IE10 +和Chrome25 +。还有polyfill可用(我写的)。

答案 4 :(得分:32)

要获得精确值,您应该使用Performance interface。现代版本的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中测量执行时间,检查这个辉煌的post。作者还提供了一些关于JavaScript时间准确性的链接,值得一读。

答案 5 :(得分:18)

使用Firebug,启用Console和Javascript。点击个人资料刷新。再次单击配置文件查看报告。

答案 6 :(得分:11)

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

答案 7 :(得分:11)

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

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

答案 8 :(得分:8)

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

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发送到远程客户端,在网页上提供等等。

答案 9 :(得分:7)

您还可以在此处使用添加运算符

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

答案 10 :(得分:6)

只能使用一个变量:

var timer = -performance.now();

// Do something

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

timer/1000-将毫秒转换为秒

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

答案 11 :(得分:5)

由于某些主要浏览器(即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);
        }
    }
}

答案 12 :(得分:5)

它可能对你有帮助。

var t0 = date.now(); doSomething(); var t1 = date.now(); console.log("Call to doSomething took approximate" + (t1 - t0)/1000 + " seconds.")

答案 13 :(得分:4)

谢谢,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也需要时间来执行,并会影响性能测试。)

注意,按顺序测量异步函数的执行时间,你应该在回调中插入var timeInMilliseconds = process.hrtime(t0)[1]/1000000;。例如,

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

});

答案 14 :(得分:2)

几个月前,我将自己的例程放在一起,使用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 { performance } = require('perf_hooks')

答案 15 :(得分:2)

这里是计时功能的装饰器

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;   
}

用法:

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

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

答案 16 :(得分:1)

如果要测量多个未嵌套的东西之间的时间,可以使用:

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

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

如果您喜欢console.time()中的蓝色,则可以使用此行代替

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

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

答案 17 :(得分:1)

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

答案 18 :(得分:1)

就我而言,我倾向于使用@ grammar 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 function 
function 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(适用于通天塔6)

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

答案 19 :(得分:1)

具有累积周期的秒表

与服务器和客户端(节点或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];
    }
};

答案 20 :(得分:1)

login.config

'startID'->标识范围的唯一ID

以上代码给出了“ myFunction”执行所需的时间。

答案 21 :(得分:0)

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

  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. 这是最有效的方法: 使用performance.now()

例如var v1 = performance.now(); //run the function here for which you have top measure the time var v2 = performance.now(); console.log("total time taken = "+(v2-v1)+"milliseconds";

  1. 使用+(添加运算符)或getTime()

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

将一元加运算符应用于Date实例时,将发生以下情况:          获取有问题的Date实例的值          将其转换为数字

注意:与一元+运算符相比,getTime()的性能更好。

答案 22 :(得分:0)

最好的方法是使用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);

尝试here

答案 23 :(得分:0)

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

function addUpTo(n) {
  let total = 0;
  for (let i = 1; i <= n; i++) {
    total += i;
  }
  return total;
}


let t1 = performance.now();
addUpTo(1000000000);
let t2 = performance.now();
console.log(`Time elapsed: ${(t2 - t1) / 1000} seconds`);
// Time elapsed: 1.1261566010713577 seconds

答案 24 :(得分:0)

表现出色

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');

答案 25 :(得分:0)

  1. 启动,请使用console.time("myTimer");
  2. 可选:要打印经过时间,请使用 console.timeLog("myTimer");
  3. 最后,要停止计时器并打印最终结果 时间:console.timeEnd("myTimer");

您可以在MDNNode.js documentation中阅读有关此内容的更多信息。

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

答案 26 :(得分:0)

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

答案 27 :(得分:-2)

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

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

答案 28 :(得分:-2)

您还应该考虑阅读 bigO 表示法。对于理解正在发生的事情,它可能比计时函数更好

答案 29 :(得分:-5)

接受的答案是错误

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

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