Во фронтенде встречаются задачи, требующие измерения времени: например, расчёт длительности загрузки какого-либо ресурса или расчёт прогресса анимации.
Велик соблазн использовать для расчёта Date.now
:
const start = Date.now();
const result = await fetch('/data');
console.log('Elapsed time in milliseconds:', Date.now() - start);
Казалось бы, задача решена и можно отправляться пить кофе. Но есть нюанс: вычисленная таким способом длительность может оказаться отрицательной.
Что не так с Date.now?
Главные проблемы функции Date.now
в контексте описанной задачи:
Date.now
не монотонна, то есть она может как возрастать, так и убывать (это и приводит к получению отрицательных длительностей в вычислениях).- Она не гарантирует равномерность роста возвращаемых значений.
Корень этих проблем в том, что Date
и его функции используют системные часы, которые подвержены внешним воздействиям:
- системное время может быть изменено пользователем;
- службы операционной системы регулярно синхронизируют время c точными часами через интернет, что может приводить к скачкам, если локальные часы сильно отстали или наоборот ушли вперёд.
Что использовать вместо Date.now?
В браузере
В спецификации High Resolution Time описана функция performance.now
, которая не только решает озвученные проблемы, но и повышает точность измерений до микросекунд (в зависимости от браузера). Подробнее о ней можно прочитать в самой спецификации или на MDN.
В Node.js
Node.js предоставляет функции process.hrtime
и process.hrtime.bigint
, которые тоже не зависят от системных часов и повышают точность измерений до наносекунд.