НейроАгент

Как измерить время выполнения функции в миллисекундах

Узнайте самые надежные методы измерения времени выполнения JavaScript функции в миллисекундах с помощью API performance.now(). Получите точные измерения времени для оптимизации.

Вопрос

Как измерить время выполнения функции в миллисекундах

Мне нужно измерить время, затраченное на выполнение функции, именно в миллисекундах.

Примечание: Этот вопрос изначально был задан в 2008 году. Хотя в то время принятый ответ заключался в использовании new Date().getTime(), текущей лучшей практикой является использование стандартного API performance.now(), который обеспечивает более высокую точность для измерения производительности.

НейроАгент

Самый надежный способ измерения времени выполнения функции в миллисекундах — использование API performance.now(), которое обеспечивает высокоточное измерение с точностью до долей миллисекунды. Этот метод фиксирует время до и после выполнения функции, затем вычисляет разницу для получения точной длительности в миллисекундах. В отличие от более старых подходов с использованием Date.now(), performance.now() специально разработан для измерения производительности и обеспечивает лучшую точность для бенчмаркинга.

Содержание


Базовая реализация

Фундаментальный подход к измерению времени выполнения включает фиксацию временных меток до и после выполнения функции:

javascript
const start = performance.now();
// Ваша функция для измерения
functionToBeMeasured();
const end = performance.now();

const executionTime = end - start;
console.log(`Время выполнения: ${executionTime} мс`);

Для асинхронных функций паттерн остается похожим:

javascript
const start = performance.now();
await asyncFunctionToMeasure();
const end = performance.now();
console.log(`Время выполнения: ${end - start} мс`);

Метод performance.now() возвращает значение DOMHighResTimeStamp, представляющее время в миллисекундах с начала загрузки страницы, но с гораздо более высокой точностью, чем Date.now(). Это делает его идеальным для точного измерения коротких интервалов выполнения.


Совместимость с браузерами

Хотя performance.now() широко поддерживается в современных браузерах, существуют важные аспекты совместимости:

Поддержка браузерами:

  • Chrome: Полная поддержка с высокой точностью
  • Firefox: Доступен, но может округлять до 1-2 миллисекунд из-за мер безопасности
  • Safari: Доступен, но могут быть различия в реализации
  • Edge: Полная поддержка, соответствующая движку Chrome

Вариации точности:
Согласно Mozilla Developer Network, браузеры могут округлять результаты по соображениям безопасности. Например, Firefox начиная с версии 59 округляет до 2 миллисекунд для смягчения уязвимостей Spectre.

Различия в поведении при “сне”:
Спецификация требует, чтобы performance.now() продолжал отсчет времени, когда операционная система переходит в режим сна или процесс браузера зависает. Однако это поведение варьируется:

  • Браузеры Windows обычно продолжают отсчет во время сна
  • Другие платформы могут приостанавливать отсчет во время системного сна

Это может значительно влиять на измерения длительных операций, особенно на мобильных устройствах или ноутбуках.


Продвинутые техники

Для более сложного измерения производительности рассмотрите эти подходы:

Измерение нескольких функций:

javascript
function measureFunctionTime(fn, iterations = 1) {
  const times = [];
  
  for (let i = 0; i < iterations; i++) {
    const start = performance.now();
    fn();
    const end = performance.now();
    times.push(end - start);
  }
  
  return {
    average: times.reduce((a, b) => a + b, 0) / times.length,
    min: Math.min(...times),
    max: Math.max(...times),
    all: times
  };
}

Использование Performance Marks:

javascript
performance.mark('start-measurement');
yourFunction();
performance.mark('end-measurement');

performance.measure('function-execution', 'start-measurement', 'end-measurement');
const measures = performance.getEntriesByName('function-execution');
console.log(`Время выполнения: ${measures[0].duration} мс`);

Этот подход интегрируется с Performance API, позволяя проводить более комплексный анализ производительности.


Кросс-браузерные решения

Для максимальной совместимости с разными браузерами используйте полифил или метод обнаружения:

Базовое обнаружение:

javascript
var performance = window.performance || {};
performance.now = performance.now || performance.webkitNow || 
                  performance.msNow || performance.oNow || 
                  performance.mozNow || function() {
  return Date.now();
};

Более надежный полифил:

javascript
if (!window.performance) {
  window.performance = {};
}

if (!window.performance.now) {
  var start = Date.now();
  window.performance.now = function() {
    return Date.now() - start;
  };
}

Согласно обсуждениям на Stack Overflow, эти полифилы обеспечивают последовательное поведение в разных браузерах, хотя они могут не обеспечивать того же уровня точности, что и нативные реализации.


Альтернативы для Node.js

В среде Node.js у вас есть несколько вариантов для измерения времени:

Использование process.hrtime:

javascript
const start = process.hrtime();
yourFunction();
const [seconds, nanoseconds] = process.hrtime(start);
const milliseconds = seconds * 1000 + nanoseconds / 1000000;
console.log(`Время выполнения: ${milliseconds} мс`);

Использование performance.now() в Node.js:

javascript
const { performance } = require('perf_hooks');
const start = performance.now();
yourFunction();
const end = performance.now();
console.log(`Время выполнения: ${end - start} мс`);

Версия с BigInt (наивысшая точность):

javascript
const start = process.hrtime.bigint();
yourFunction();
const end = process.hrtime.bigint();
const duration = Number(end - start) / 1000000n;
console.log(`Время выполнения: ${duration} мс`);

Версия с BigInt обеспечивает точность до наносекунд, что делает ее подходящей для очень точных измерений.


Лучшие практики

При измерении времени выполнения функции следуйте этим рекомендациям:

1. Выполняйте несколько измерений:
Единичные измерения могут быть искажены системным шумом. Запускайте функцию несколько раз и вычисляйте средние значения:

javascript
function benchmark(fn, iterations = 1000) {
  const times = [];
  for (let i = 0; i < iterations; i++) {
    const start = performance.now();
    fn();
    times.push(performance.now() - start);
  }
  return {
    average: times.reduce((a, b) => a + b, 0) / times.length,
    min: Math.min(...times),
    max: Math.max(...times)
  };
}

2. Учитывайте эффекты прогрева:
Движки JavaScript оптимизируют код со временем. Запустите вашу функцию несколько раз перед началом измерений, чтобы позволить оптимизациям произойти.

3. Учитывайте системную изменчивость:
Измеряйте при стабильных системных условиях. Фоновые процессы, ограничение CPU и использование памяти могут влиять на результаты.

4. Используйте подходящую точность:
Для очень быстрых функций рассмотрите возможность их многократного запуска для получения измеримых результатов.

5. Избегайте накладных расходов измерения:
Убедитесь, что код измерения сам по себе не влияет на результаты. Содержите логику измерения в минимальных объемах.

6. Учитывайте окружение:
Браузер против Node.js, разные браузеры и системные условия влияют на точность измерений. Всегда учитывайте контекст ваших измерений.


Источники

  1. How to measure time taken by a function to execute - Stack Overflow
  2. Measuring JavaScript Functions’ Performance — SitePoint
  3. How to Measure JavaScript Execution Time - DEV Community
  4. Measure execution times in browsers & Node.js - DEV Community
  5. Node.js Performance Hooks and Measurement APIs - Medium
  6. How to Measure Time Taken by a Function to Execute - W3Docs
  7. Measuring execution times in Javascript like a pro - Medium
  8. Performance: now() method - MDN
  9. performance.now() - Web APIs
  10. Is there a cross browser solution for performance.now() in Chrome? - Stack Overflow

Заключение

Измерение времени выполнения функции в миллисекундах с помощью современного JavaScript с использованием performance.now() является простым. Это API предоставляет высокоточное время, специально разработанное для измерения производительности, предлагая лучшую точность, чем традиционные подходы на основе даты. При реализации измерений времени всегда учитывайте совместимость с браузерами, выполняйте несколько итераций для точности и учитывайте системные переменные, которые могут повлиять на ваши результаты. Для сред Node.js process.hrtime.bigint() предлагает еще более высокую точность с точностью до наносекунд. Помните, что хотя эти измерения ценны для оптимизации, их следует использовать как один из многих инструментов для понимания и улучшения производительности приложения.