如何用回调来衡量javascript代码的执行时间

Sto*_*dow 296 javascript profiling node.js

我有一段javascript代码,我正在使用node.js解释器执行.

for(var i = 1; i < LIMIT; i++){
    db.users.save({id : i, name : "MongoUser [" + i + "]"}, function(err, saved) {
          if( err || !saved ) console.log("Error");
          else console.log("Saved");
    });
}
Run Code Online (Sandbox Code Playgroud)

我想知道如何测量这些数据库插入操作所花费的时间.我可以计算这段代码之前和之前的Date值的差异,但由于代码的异步性质,这将是不正确的.

小智 674

使用Node.js console.time()console.timeEnd():

var i;
console.time("dbsave");

for(i = 1; i < LIMIT; i++){
    db.users.save({id : i, name : "MongoUser [" + i + "]"}, end);
}

end = function(err, saved) {
    console.log(( err || !saved )?"Error":"Saved");
    if(--i === 1){console.timeEnd("dbsave");}
};
Run Code Online (Sandbox Code Playgroud)

  • >我想知道如何测量这些数据库插入操作所花费的时间.--- console.timeEnd("dbsave")只是输出到控制台的时间.您不能进一步使用它并且不太灵活.如果你需要实际的时间值,就像在原始问题中一样,你不能使用console.timeEnd("dbsave") (41认同)
  • 针对节点的清洁和内置解决方案. (29认同)
  • 那么下面的答案中console.time()和process.hrtime()之间的区别是什么? (4认同)
  • 值得添加一个注释,然后打印执行时间,以便现在新用户. (3认同)

D.D*_*iso 196

有一种专门为此而设计的方法.查看process.hrtime(); .

所以,我基本上把它放在我的应用程序的顶部.

var start = process.hrtime();

var elapsed_time = function(note){
    var precision = 3; // 3 decimal places
    var elapsed = process.hrtime(start)[1] / 1000000; // divide by a million to get nano to milli
    console.log(process.hrtime(start)[0] + " s, " + elapsed.toFixed(precision) + " ms - " + note); // print message + time
    start = process.hrtime(); // reset the timer
}
Run Code Online (Sandbox Code Playgroud)

然后我用它来看看函数需要多长时间.这是打印名为"output.txt"的文本文件内容的基本示例:

var debug = true;
http.createServer(function(request, response) {

    if(debug) console.log("----------------------------------");
    if(debug) elapsed_time("recieved request");

    var send_html = function(err, contents) {
        if(debug) elapsed_time("start send_html()");
        response.writeHead(200, {'Content-Type': 'text/html' } );
        response.end(contents);
        if(debug) elapsed_time("end send_html()");
    }

    if(debug) elapsed_time("start readFile()");
    fs.readFile('output.txt', send_html);
    if(debug) elapsed_time("end readFile()");

}).listen(8080);
Run Code Online (Sandbox Code Playgroud)

这是一个可以在终端(BASH shell)中运行的快速测试:

for i in {1..100}; do echo $i; curl http://localhost:8080/; done
Run Code Online (Sandbox Code Playgroud)

  • 是的,它更加精确,您可以将结果存储在变量中 (30认同)
  • 它以任何方式优于console.time解决方案? (2认同)
  • 为什么要调用`process.hrtime(start)` 两次?有什么特别的原因吗? (2认同)
  • process.hrtime([time]),其中 time 是可选参数,必须是先前 process.hrtime() 调用 diff 与当前时间的结果。它给出了当前调用和前一个 hrtime 调用之间的差异。 (2认同)

jfc*_*edo 64

调用console.time('label')将以毫秒为单位记录当前时间,然后稍后调用console.timeEnd('label')将显示该点的持续时间.

以毫秒为单位的时间将自动与标签一起打印,因此您无需单独调用console.log来打印标签:

console.time('test');
//some code
console.timeEnd('test'); //Prints something like that-> test: 11374.004ms
Run Code Online (Sandbox Code Playgroud)

有关更多信息,请参阅Mozilla的开发人员文档console.time.

  • @DanDascalescu,这比公认的答案更简洁、更易读、更容易理解——后者充斥着嘈杂的“示例”代码。我个人更喜欢这个答案。 (21认同)
  • 在我回答使用我的代码后修改了接受的答案 (7认同)
  • 这对[已接受的答案](/sf/answers/1289935671/)添加了什么? (3认同)

Cod*_*y G 19

惊讶没有人提到新的内置库:

在Node> = 8.5中可用,并且应该在Modern Browers中

https://developer.mozilla.org/en-US/docs/Web/API/Performance

https://nodejs.org/docs/latest-v8.x/api/perf_hooks.html#

节点8.5~9.x(Firefox,Chrome)

// const { performance } = require('perf_hooks'); // enable for node
const delay = time => new Promise(res=>setTimeout(res,time))
async function doSomeLongRunningProcess(){
  await delay(1000);
}
performance.mark('A');
(async ()=>{
  await doSomeLongRunningProcess();
  performance.mark('B');
  performance.measure('A to B', 'A', 'B');
  const measure = performance.getEntriesByName('A to B')[0];
  // firefox appears to only show second precision.
  console.log(measure.duration);
  performance.clearMeasures(); // apparently you should remove entries...
  // Prints the number of milliseconds between Mark 'A' and Mark 'B'
})();
Run Code Online (Sandbox Code Playgroud)

https://repl.it/@CodyGeisler/NodeJsPerformanceHooks

节点10.x.

https://nodejs.org/docs/latest-v10.x/api/perf_hooks.html

const { PerformanceObserver, performance } = require('perf_hooks');
const delay = time => new Promise(res => setTimeout(res, time))
async function doSomeLongRunningProcess() {
    await delay(1000);
}
const obs = new PerformanceObserver((items) => {
    console.log('PerformanceObserver A to B',items.getEntries()[0].duration);
    performance.clearMarks();
});
obs.observe({ entryTypes: ['measure'] });

performance.mark('A');

(async function main(){
    try{
        await performance.timerify(doSomeLongRunningProcess)();
        performance.mark('B');
        performance.measure('A to B', 'A', 'B');
    }catch(e){
        console.log('main() error',e);
    }
})();
Run Code Online (Sandbox Code Playgroud)

  • 在 Node v10.4.1 中给我 `TypeError: performance.getEntriesByName is not a function` (2认同)
  • `稳定性:1 - 实验性` 也许?:) https://nodejs.org/docs/latest-v8.x/api/perf_hooks.html#perf_hooks_performance_timing_api (2认同)

Sin*_*ing 18

对于任何想要获取时间值而不是控制台输出的人:

使用process.hrtime()作为@ D.Deriso的建议,下面是我更简单的方法:

function functionToBeMeasured() {
    var startTime = process.hrtime();
    // do some task...
    // ......
    var elapsedSeconds = parseHrtimeToSeconds(process.hrtime(startTime));
    console.log('It takes ' + elapsedSeconds + 'seconds');
}

function parseHrtimeToSeconds(hrtime) {
    var seconds = (hrtime[0] + (hrtime[1] / 1e9)).toFixed(3);
    return seconds;
}
Run Code Online (Sandbox Code Playgroud)


And*_*rov 16

var start = +new Date();
var counter = 0;
for(var i = 1; i < LIMIT; i++){
    ++counter;
    db.users.save({id : i, name : "MongoUser [" + i + "]"}, function(err, saved) {
          if( err || !saved ) console.log("Error");
          else console.log("Saved");
          if (--counter === 0) 
          {
              var end = +new Date();
              console.log("all users saved in " + (end-start) + " milliseconds");
          }
    });
}
Run Code Online (Sandbox Code Playgroud)

  • 我不得不查找语法'+ new Date()'来弄清楚这意味着什么.根据对此答案的评论(http://stackoverflow.com/a/221565/5114),出于性能原因和可读性而使用该表单并不是一个好主意.我更喜欢更冗长的东西,所以对读者来说更清楚.另请参阅此答案:http://stackoverflow.com/a/5036460/5114 (5认同)
  • 我经常使用`var start = process.hrtime(); ... ... var end = process.hrtime(start);`获得高分辨率时间(如果我需要亚毫秒精度) (3认同)

Onu*_*rım 9

旧问题,但对于简单的API和轻量级解决方案; 你可以使用 内部使用高分辨率实时(process.hrtime)的perfy.

var perfy = require('perfy');

function end(label) {
    return function (err, saved) {
        console.log(err ? 'Error' : 'Saved'); 
        console.log( perfy.end(label).time ); // <——— result: seconds.milliseconds
    };
}

for (var i = 1; i < LIMIT; i++) {
    var label = 'db-save-' + i;
    perfy.start(label); // <——— start and mark time
    db.users.save({ id: i, name: 'MongoUser [' + i + ']' }, end(label));
}
Run Code Online (Sandbox Code Playgroud)

请注意,每次perfy.end(label)调用时,该实例都会被自动销毁.

披露:在D.Deriso的回答的启发下写了这个模块.文档在这里.