如何使用回调测量 JavaScript 代码的执行时间?

IT技术 javascript node.js profiling
2021-03-03 10:40:54

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

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

如何测量这些数据库插入操作所花费的时间?我可以计算这段代码前后日期值的差异,但由于代码的异步性质,这是不正确的。

6个回答

使用 Node.jsconsole.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");}
};
值得添加一个注释,然后打印出执行时间,以便现在新用户。
2021-04-28 10:40:54
>我想知道如何测量这些数据库插入操作所花费的时间。--- console.timeEnd("dbsave") 只是输出到控制台的时间。您不能进一步使用它,并且不那么灵活。如果您需要实际的计时值,就像在原始问题中一样,您不能使用 console.timeEnd("dbsave")
2021-04-29 10:40:54
仅供参考,计时器已被 timeEnd 杀死,因此您之后无法再次调用它,这是一个新的错误修复,曾经是一个意外功能。
2021-05-01 10:40:54
节点的清洁和内置解决方案。
2021-05-05 10:40:54
那么下面的答案中的 console.time() 和 process.hrtime() 有什么区别呢?
2021-05-06 10:40:54

有一种方法是为此而设计的。查看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
}

然后我用它来查看函数需要多长时间。这是一个打印名为“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);

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

for i in {1..100}; do echo $i; curl http://localhost:8080/; done
它在任何方面都优于 console.time 解决方案吗?
2021-04-23 10:40:54
这个对我有用,因为我想多次调用计时器
2021-04-26 10:40:54
是的,它更精确,您可以将结果存储在变量中
2021-05-06 10:40:54
为什么要打process.hrtime(start)两次电话有什么特别的原因吗?
2021-05-08 10:40:54
process.hrtime([time]),其中 time 是一个可选参数,它必须是先前 process.hrtime() 调用 diff 与当前时间的结果。它给出了当前调用和前一个 hrtime 调用之间的差异。
2021-05-09 10:40:54

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

以毫秒为单位的时间将自动打印在标签旁边,因此您不必单独调用 console.log 来打印标签:

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

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

对接受的答案有什么影响?
2021-04-26 10:40:54

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

在 Node >= 8.5 中可用,并且应该在现代浏览器中

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);
  // apparently you should clean up...
  performance.clearMarks();
  performance.clearMeasures();         
  // Prints the number of milliseconds between Mark 'A' and Mark 'B'
})();

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

节点 12.x

https://nodejs.org/docs/latest-v12.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);
      // apparently you should clean up...
      performance.clearMarks();
      // performance.clearMeasures(); // Not a function in Node.js 12
});
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);
    }
})();
Stability: 1 - Experimental或许?:) nodejs.org/docs/latest-v8.x/api/...
2021-04-29 10:40:54
TypeError: performance.getEntriesByName is not a function在 Node v10.4.1 中给我
2021-05-02 10:40:54
是的,它肯定已经改变了。v10 中有一个新的观察者,您可以在nodejs.org/docs/latest-v10.x/api/documentation.html 上查看文档有机会我会更新的!
2021-05-15 10:40:54
我制作了这个示例,以便您可以在线运行它。它是节点 9.7.1。如果它在 v10.4.1 中不起作用,那么我想知道可能会发生什么变化!
2021-05-18 10:40:54
很好,但有一件事是developer.mozilla.org/en-US/docs/Web/API/Performance/measure表明我们应该performance.clearMarks()performance.clearMeasures()?
2021-05-18 10:40:54

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

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