Считаем время в JavaScript

Во фронтенде встречаются задачи, требующие измерения времени: например, расчёт длительности загрузки какого-либо ресурса или расчёт прогресса анимации.

Велик соблазн использовать для расчёта Date.now:

const start = Date.now();
const result = await fetch('/data');

console.log('Elapsed time in milliseconds:', Date.now() - start);

Казалось бы, задача решена и можно отправляться пить кофе. Но есть нюанс: вычисленная таким способом длительность может оказаться отрицательной.

Что не так с Date.now?

Главные проблемы функции Date.now в контексте описанной задачи:

  1. Date.now не монотонна, то есть она может как возрастать, так и убывать (это и приводит к получению отрицательных длительностей в вычислениях).
  2. Она не гарантирует равномерность роста возвращаемых значений.

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

Что использовать вместо Date.now?

В браузере

В спецификации High Resolution Time описана функция performance.now, которая не только решает озвученные проблемы, но и повышает точность измерений до микросекунд (в зависимости от браузера). Подробнее о ней можно прочитать в самой спецификации или на MDN.

В Node.js

Node.js предоставляет функции process.hrtime и process.hrtime.bigint, которые тоже не зависят от системных часов и повышают точность измерений до наносекунд.