¿Cómo mido el tiempo de ejecución del código JavaScript con devoluciones de llamada?

7 minutos de lectura

avatar de usuario
Sombra tormenta

Tengo una pieza de código JavaScript que estoy ejecutando usando el node.js intérprete.

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

¿Cómo puedo medir el tiempo que tardan estas operaciones de inserción en la base de datos? Podría calcular la diferencia de los valores de fecha antes y después de este fragmento de código, pero eso sería incorrecto debido a la naturaleza asíncrona del código.

  • Simplemente lea la hora de inicio antes de la llamada de db y la hora de finalización DENTRO de la devolución de llamada.

    – BFil

    16 mayo 2012 a las 10:59

  • ¿Existe la posibilidad de que el tiempo que el DB finaliza la inserción y el tiempo que se ejecuta la devolución de llamada no sea el mismo y esto introduciría un error en la medición?

    – Sombra tormenta

    16 mayo 2012 a las 11:13

  • No, no debe preocuparse por eso, si el código de la biblioteca db está bien diseñado y no maneja ninguna otra operación antes de activar la devolución de llamada, debe obtener una buena medida. También puede perfilar la inserción colocando las marcas de tiempo dentro del código de la biblioteca donde realmente se realiza la inserción, en lugar del suyo, pero, nuevamente, no me preocuparía por eso.

    – BFil

    16 mayo 2012 a las 11:32

  • recomendaría probar Tiempo de nodo que parece ser una buena opción para lo que está tratando de hacer.

    – Julián Caballero

    18 mayo 2012 a las 10:20

  • escribí timerlog que es similar a console.time() pero con características adicionales; github.com/brillout/timerlog

    – brillo

    1 de marzo de 2017 a las 13:10

avatar de usuario
jfcorugedo

invocando console.time('label') registrará la hora actual en milisegundos, luego llamará console.timeEnd('label') mostrará la duración desde ese punto.

El tiempo en milisegundos se imprimirá automáticamente junto con la etiqueta, por lo que no tienes que hacer una llamada separada a console.log para imprimir una etiqueta:

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

Para más información, ver Documentos para desarrolladores de Mozilla en console.time.

  • ¿Qué agrega esto a la respuesta aceptada?

    – Dan Dascalescu

    5 de julio de 2018 a las 23:11

  • @DanDascalescu Esto es mucho más sucinto, legible y digerible que la respuesta aceptada, que está plagada de ruidosos códigos de “ejemplo”. Personalmente, prefiero mucho más esta respuesta.

    –Andy Lorenz

    4 ene a las 9:40

  • ¿Es tan superior a la solución console.time de alguna manera?

    – avaricioso

    31 de marzo de 2015 a las 17:29

  • Sí, es mucho más preciso y puedes almacenar el resultado en una variable

    – Dallas-Clark

    1 de julio de 2015 a las 6:17

  • ¿Por qué llamas? process.hrtime(start) ¿dos veces? ¿Hay alguna razón en particular para ello?

    – Sohail Si

    6 de febrero de 2019 a las 19:09

  • proceso.hrtime([time]), donde la hora es un parámetro opcional que debe ser el resultado de una llamada previa a process.hrtime() para diferenciar la hora actual. Da la diferencia entre la llamada actual y la llamada hrtime anterior.

    – Nilesh Jain

    28 de noviembre de 2019 a las 8:50


  • buena solución, pero la última línea ( start = process.hrtime(); // reset the timer ) no tiene ningún sentido

    – Esben Skov Pedersen

    9 de marzo de 2020 a las 13:55

avatar de usuario
Cody G

Sorprendido de que nadie haya mencionado aún las nuevas bibliotecas integradas:

Disponible en Node >= 8.5, y debería estar en Modern Browers

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

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

Nodo 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

Nodo 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);
    }
})();

  • me da TypeError: performance.getEntriesByName is not a function en Nodo v10.4.1

    – Jeremy Thille

    29 de julio de 2018 a las 7:47

  • Hice el ejemplo para que puedas ejecutarlo en línea. Es Nodo 9.7.1. Si no funciona en v10.4.1, entonces me pregunto qué podría estar cambiando.

    – Cody G

    29 de julio de 2018 a las 22:07

  • Stability: 1 - Experimental ¿quizás? 🙂 nodejs.org/docs/latest-v8.x/api/…

    – Jeremy Thille

    30 de julio de 2018 a las 6:33

  • Sí, seguro que ha cambiado. Hay un nuevo observador en v10, puedes ver los documentos en nodejs.org/docs/latest-v10.x/api/documentation.html. ¡Actualizaré cuando tenga la oportunidad!

    – Cody G

    3 de agosto de 2018 a las 17:38

  • Genial, una cosa es que developer.mozilla.org/en-US/docs/Web/API/Performance/measure Indica que debemos performance.clearMarks() junto con performance.clearMeasures()?

    –Craig van Tonder

    17 de noviembre de 2020 a las 22:39


Puedes usar un wrapper función para informar fácilmente el tiempo de ejecución de cualquier función existente.

Un contenedor se usa para extender una función existente para hacer algo antes y después de la ejecución de la función existente, y es una forma conveniente de componer la lógica.

Aquí hay un ejemplo del uso de la withDurationReporting envoltura:

// without duration reporting
const doSomethingThatMayTakeAWhile = async (someArg: string, anotherArg: number) => { 
  /** your logic goes here */
}

// with duration reporting
const doSomethingThatMayTakeAWhileWithReporting = withDurationReporting(
  'doSomethingThatMayTakeAWhile', 
  doSomethingThatMayTakeAWhile
);
// note: you can define the function with duration reporting directly, too
const doSomethingThatMayTakeAWhile = withDurationReporting(
  'doSomethingThatMayTakeAWhile', 
  async (someArg: string, anotherArg: number) => { 
    /** your logic goes here */
  }
)

Y aquí está el envoltorio en sí:

import { hrtime } from 'process';

const roundToHundredths = (num: number) => Math.round(num * 100) / 100; // https://stackoverflow.com/a/14968691/3068233

/**
 * a wrapper which reports how long it took to execute a function, after the function completes
 */
export const withDurationReporting = <R extends any, T extends (...args: any[]) => Promise<R>>(
  title: string,
  logic: T,
  options: {
    reportingThresholdSeconds: number;
    logMethod: (message: string, metadata?: Record<string, any>) => void;
  } = {
    reportingThresholdSeconds: 1, // report on anything that takes more than 1 second, by default
    logMethod: console.log, // log with `console.log` by default
  }, 
) => {
  return (async (...args: Parameters<T>): Promise<R> => {
    const startTimeInNanoseconds = hrtime.bigint();
    const result = await logic(...args);
    const endTimeInNanoseconds = hrtime.bigint();
    const durationInNanoseconds = endTimeInNanoseconds - startTimeInNanoseconds;
    const durationInSeconds = roundToHundredths(Number(durationInNanoseconds) / 1e9); // https://stackoverflow.com/a/53970656/3068233
    if (durationInSeconds >= options.reportingThresholdSeconds)
      options.logMethod(`${title} took ${durationInSeconds} seconds to execute`, { title, durationInSeconds });
    return result;
  }) as T;
};

  • me da TypeError: performance.getEntriesByName is not a function en Nodo v10.4.1

    – Jeremy Thille

    29 de julio de 2018 a las 7:47

  • Hice el ejemplo para que puedas ejecutarlo en línea. Es Nodo 9.7.1. Si no funciona en v10.4.1, entonces me pregunto qué podría estar cambiando.

    – Cody G

    29 de julio de 2018 a las 22:07

  • Stability: 1 - Experimental ¿quizás? 🙂 nodejs.org/docs/latest-v8.x/api/…

    – Jeremy Thille

    30 de julio de 2018 a las 6:33

  • Sí, seguro que ha cambiado. Hay un nuevo observador en v10, puedes ver los documentos en nodejs.org/docs/latest-v10.x/api/documentation.html. ¡Actualizaré cuando tenga la oportunidad!

    – Cody G

    3 de agosto de 2018 a las 17:38

  • Genial, una cosa es que developer.mozilla.org/en-US/docs/Web/API/Performance/measure Indica que debemos performance.clearMarks() junto con performance.clearMeasures()?

    –Craig van Tonder

    17 de noviembre de 2020 a las 22:39


Para cualquiera que desee obtener el valor del tiempo transcurrido en lugar de la salida de la consola:

usar proceso.hrtime() como sugerencia de @D.Deriso, a continuación se muestra mi enfoque más simple:

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

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad