Измерение времени выполнения асинхронного кода JavaScript

Пройдите тест, узнайте какой профессии подходите

Я предпочитаю
0%
Работать самостоятельно и не зависеть от других
Работать в команде и рассчитывать на помощь коллег
Организовывать и контролировать процесс работы

Быстрый ответ

Для точного замера времени выполнения операций JavaScript, которые применяют коллбеки, воспользуйтесь методом performance.now(). Устанавливайте временные метки в момент начала операции и сразу по её завершении, а именно, прямо в коде коллбека. Разница между этими значениями даст вам реальное время выполнения.

JS
Скопировать код
const start = performance.now();

asyncFunction(() => {
  const duration = performance.now() – start;
  console.log(`Время выполнения: ${duration} мс`);
});

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

Кинга Идем в IT: пошаговый план для смены профессии

Измерение времени с высокой точностью при помощи hrtime

В Node.js для измерения времени с высокой точностью подходит process.hrtime(). Этот метод предоставляет возможность измерять время до наносекунд. Так можно перевести результаты в миллисекунды:

JS
Скопировать код
const start = process.hrtime();

asyncOperation(() => {
  const diff = process.hrtime(start);
  const durationInMilliseconds = (diff[0] * 1e9 + diff[1]) / 1e6; // Преобразование из наносекунд в миллисекунды
  console.log(`Время выполнения: ${durationInMilliseconds} мс`);
});

Не забывайте сбрасывать hrtime перед проведением повторных замеров и обеспечьте корректную обработку ошибок. Чтобы точно отслеживать асинхронные операции, используйте Performance API.

Измерение времени выполнения итеративных асинхронных операций

Если требуется измерить время выполнения повторяющихся асинхронных операций, например, вставки в базу данных, вы можете воспользоваться следующим кодом:

JS
Скопировать код
let completedOps = 0;
const LIMIT = 10;
console.time('dbInsertTimer');

for (let i = 0; i < LIMIT; i++) {
  insertIntoDatabaseAsync(data, (err) => {
    if (err) {
      console.error(`Ошибка при вставке на итерации ${i}:`, err);
    } else {
      console.log(`Запись ${i} успешно сохранена`);
      if (++completedOps === LIMIT) {
        console.timeEnd('dbInsertTimer');
      }
    }
  });
}

Значение LIMIT и инкрементирование completedOps обеспечивают окончание замера времени только после выполнения всех операций.

Решение проблем с таймерами в сложных сценариях

Некоторые сложности, такие как нестабильность работы коллбеков или большие колебания времени выполнения, могут затруднить процесс измерения. В таких случаях можно использовать переменные для отладки, чтобы контролировать объём ведомой информации о времени выполнения. Также можно измерять время выполнения файловых операций с коллбеками, например, при реализации функции отправки HTML.

Визуализация

Процесс измерения времени выполнения асинхронных JavaScript коллбеков можно сравнить с тем, как хронометрист (⏱️) фиксирует время на эстафете 🏃‍♂️🔄🏃‍♀️:

JS
Скопировать код
console.time('asyncCodeTimer'); // На старт... внимание... марш!

// Асинхронная функция с коллбеком
asyncFunctionWithCallback(() => {
  console.timeEnd('asyncCodeTimer'); // Стоп хронометр!
});

Если провизуализировать процесс, будет чётко видно:

Markdown
Скопировать код
🏁[Начало кода] -> 🏃‍♂️[Асинхронная функция в процессе] -> 🔄[Ожидание вызова коллбека...] -> 🏃‍♀️[Выполнение коллбека] -> 🏆[Завершение кода]
⏱️[Измеренное время]

Таким образом, старт и финиш -- это использование методов console.time() и console.timeEnd(), которые обозначают начало и конец нашего замера, включая весь жизненный цикл асинхронной операции.

Точное измерение времени с использованием Performance API

Для точного контроля времени используйте Performance API с методами performance.mark() и performance.measure():

JS
Скопировать код
// Для Node.js версии 12 и выше
const { performance, PerformanceObserver } = require('perf_hooks');

performance.mark('A'); // Маркируем начало
asyncOperation(() => {
  performance.mark('B'); // Маркер конца
  performance.measure('A to B', 'A', 'B'); // Считаем разницу
  const [measure] = performance.getEntriesByName('A to B');
  console.log(`Время выполнения: ${measure.duration} мс`);
  performance.clearMarks();
  performance.clearMeasures(); // Очищаем записи
});

Класс PerformanceObserver будет незаменимым инструментом для мониторинга производительности в реальном времени в процессе работы приложения.

Конвертирование hrtime в секунды для наглядности

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

JS
Скопировать код
function hrtimeToSeconds(hrtime) {
  return (hrtime[0] + (hrtime[1] / 1e9)).toFixed(3);
}

const start = process.hrtime();
asyncOperation(() => {
  console.log(`Время выполнения: ${hrtimeToSeconds(process.hrtime(start))} сек.`);
});

Применение Async/Await для упрощения измерений

Операторы async/await упрощают процедуру измерения времени, избавив вас от прямой работы с коллбеками:

JS
Скопировать код
const measure = async (operation) => {
  const start = performance.now();
  await operation();
  const duration = performance.now() – start;
  console.log(`Время выполнения: ${duration} мс`);
};

measure(asyncOperation);

Полезные материалы

  1. Performance: now() method – Web APIs | MDN — Детальное руководство MDN по использованию performance.now.
  2. Process | Node.js v21.6.1 Documentation — Официальная документация Node.js по process.hrtime().
  3. JavaScript Performance — Руководство W3 Schools по оптимизации производительности JavaScript.
  4. Measure performance with the RAIL model — Метод оценки производительности RAIL от Google.
  5. Event Loop and the Big Picture — NodeJS Event Loop Part 1 | by Deepal Jayasekara — Подробный анализ цикла событий в Node.js.
  6. Microtasks — Учебное руководство о микрозадачах и цикле событий JavaScript.