Библиотека Day.js строит работу вокруг неизменяемых (immutable) объектов даты-времени. Каждый вызов модифицирующей операции не изменяет исходный экземпляр, а возвращает новый объект. Это напрямую влияет на стратегию кеширования и переиспользования: «обновление» состояния происходит через создание новых экземпляров, а не через мутацию.
Ключевое свойство:
add, subtract,
set) возвращает новый экземплярimport dayjs fr om 'dayjs';
const a = dayjs('2026-01-01');
const b = a.add(1, 'day');
console.log(a.format()); // 2026-01-01
console.log(b.format()); // 2026-01-02
Это поведение определяет базовую стратегию оптимизации: кеширование должно строиться вокруг входных данных, а не попыток «обновлять» объекты.
Создание экземпляра Day.js включает несколько этапов:
На практике основная нагрузка возникает при:
dayjs() в циклахfor (let i = 0; i < 100000; i++) {
dayjs('2026-01-01').format('YYYY-MM-DD');
}
В подобных сценариях узким местом становится не форматирование, а повторное создание идентичных объектов.
Самый эффективный уровень оптимизации — устранение повторного создания объектов из одинаковых входных данных.
const cache = new Map();
function getDayjs(dateString) {
if (cache.has(dateString)) {
return cache.get(dateString);
}
const value = dayjs(dateString);
cache.set(dateString, value);
return value;
}
Особенность: кешируются уже готовые объекты Day.js.
Проблема такого подхода:
Строки дат могут быть неоднозначными (форматы, локали), тогда как timestamp стабилен.
const cache = new Map();
function getDayjsFromTs(ts) {
let cached = cache.get(ts);
if (!cached) {
cached = dayjs(ts);
cache.set(ts, cached);
}
return cached;
}
Преимущество:
Несмотря на удобство, кеширование экземпляров имеет ограничения:
Если закеширован момент времени, он не «обновится»:
const now = dayjs();
setTimeout(() => {
console.log(now.format()); // время создания, не текущее
}, 5000);
Поэтому кеширование now недопустимо, если требуется
текущее время.
Один и тот же timestamp может интерпретироваться по-разному:
Кеш без учёта контекста может возвращать некорректные данные.
const cache = new Map();
function getDate(ts, tz) {
const key = `${ts}_${tz}`;
if (!cache.has(key)) {
cache.set(key, dayjs(ts).tz(tz));
}
return cache.get(key);
}
Частая операция — повторное форматирование одной и той же даты.
const formatCache = new Map();
function formatDate(ts, format) {
const key = `${ts}_${format}`;
if (formatCache.has(key)) {
return formatCache.get(key);
}
const result = dayjs(ts).format(format);
formatCache.set(key, result);
return result;
}
Это особенно эффективно при:
В ряде случаев лучше не кешировать, а переиспользовать ссылку на уже созданный объект.
Плохой подход:
const result = arr.map(x => dayjs(x).format('YYYY-MM-DD'));
Если данные повторяются:
const cache = new Map();
const result = arr.map(x => {
let d = cache.get(x);
if (!d) {
d = dayjs(x);
cache.set(x, d);
}
return d.format('YYYY-MM-DD');
});
Day.js часто используется в цепочках:
dayjs('2026-01-01').add(3, 'day').subtract(1, 'month').format();
Повторное выполнение таких цепочек может быть дорогим.
const chainCache = new Map();
function getProcessedDate(input) {
if (chainCache.has(input)) {
return chainCache.get(input);
}
const value = dayjs(input)
.add(3, 'day')
.subtract(1, 'month');
chainCache.set(input, value);
return value;
}
Без контроля кеш может стать причиной утечек памяти.
class LRUCache {
constructor(lim it = 1000) {
this.limit = limit;
this.map = new Map();
}
get(key) {
const value = this.map.get(key);
if (!value) return null;
this.map.delete(key);
this.map.set(key, value);
return value;
}
set(key, value) {
if (this.map.has(key)) {
this.map.delete(key);
}
this.map.set(key, value);
if (this.map.size > this.limit) {
const firstKey = this.map.keys().next().value;
this.map.delete(firstKey);
}
}
}
Использование:
const cache = new LRUCache(500);
function getDayjs(ts) {
let value = cache.get(ts);
if (!value) {
value = dayjs(ts);
cache.set(ts, value);
}
return value;
}
Day.js расширяется через плагины (utc,
timezone, customParseFormat). Это влияет на
корректность кеширования.
function getUTCDate(ts) {
return dayjs(ts).utc();
}
Если кешировать без учёта .utc(), возможны ошибки:
const cache = new Map();
function getUTC(ts) {
const key = ts + '_utc';
if (!cache.has(key)) {
cache.set(key, dayjs(ts).utc());
}
return cache.get(key);
}
Локализация влияет на форматирование и разбор дат.
import 'dayjs/locale/ru';
import dayjs from 'dayjs';
dayjs.locale('ru');
Если в приложении переключаются локали, кеш должен учитывать их:
function formatLocalized(ts, format, locale) {
const key = `${ts}_${format}_${locale}`;
return cache.get(key) ?? (() => {
const value = dayjs(ts).locale(locale).format(format);
cache.set(key, value);
return value;
})();
}
Иногда кеширование избыточно, и эффективнее просто уменьшить количество созданий объектов.
const ts = Date.now();
// позже
dayjs(ts).format();
Это уменьшает необходимость хранения промежуточных объектов.
Централизация создания объектов снижает дублирование логики и упрощает кеширование.
function createDate(input) {
return dayjs(input);
}
Расширенная версия с кешем:
const cache = new Map();
function createDate(input) {
if (cache.has(input)) {
return cache.get(input);
}
const value = dayjs(input);
cache.set(input, value);
return value;
}
dayjs() без аргументовconst now = dayjs();
Ошибка: значение фиксируется в момент создания.
Несмотря на неизменяемость Day.js, кеш может стать источником логических ошибок при смешивании разных контекстов:
Простейший Map без ограничения приводит к:
Комбинированный подход:
const dateCache = new Map();
const formatCache = new Map();
function getDate(ts, tz) {
const key = `${ts}_${tz}`;
if (!dateCache.has(key)) {
const value = tz ? dayjs(ts).tz(tz) : dayjs(ts);
dateCache.set(key, value);
}
return dateCache.get(key);
}
function formatDate(ts, format, tz) {
const key = `${ts}_${format}_${tz}`;
if (formatCache.has(key)) {
return formatCache.get(key);
}
const value = getDate(ts, tz).format(format);
formatCache.set(key, value);
return value;
}