В библиотеке Globalize каждый экземпляр представляет собой контекст локали, привязанный к данным CLDR и набору функций форматирования и парсинга. Такой экземпляр инкапсулирует:
ru, en,
de)Создание экземпляра — не тривиальная операция: она требует подготовки данных и построения внутренних структур. Поэтому повторное создание одинаковых экземпляров становится одной из ключевых причин деградации производительности в приложениях с интернационализацией.
При интенсивной работе с форматированием чисел, дат и сообщений часто возникает ситуация, когда одна и та же локаль используется многократно. Например:
Повторная инициализация Globalize приводит к:
Кеширование экземпляров устраняет эти проблемы, превращая дорогую операцию инициализации в дешёвую операцию доступа к уже готовому объекту.
Наиболее распространённый подход — хранение экземпляров в структуре
вида Map, где ключом выступает код локали.
import Globalize fr om "globalize";
const cache = new Map();
function getGlobalize(locale) {
if (cache.has(locale)) {
return cache.get(locale);
}
const instance = new Globalize(locale);
cache.set(locale, instance);
return instance;
}
Такая модель обеспечивает:
Globalize часто используется не как монолит, а как набор функциональных областей:
numberdatemessagecurrencyЭкземпляр может быть инициализирован частично, что создаёт необходимость учитывать конфигурацию при кешировании.
const cache = new Map();
function getGlobalize(locale, modulesKey) {
const key = `${locale}:${modulesKey}`;
if (cache.has(key)) {
return cache.get(key);
}
const instance = new Globalize(locale);
cache.set(key, instance);
return instance;
}
modulesKey формируется из списка подключённых
возможностей, например:
"number""number,date""number,date,message"Это предотвращает ситуацию, когда один и тот же экземпляр используется в разных функциональных конфигурациях, что может приводить к отсутствию нужных методов.
В высоконагруженных приложениях выгодно откладывать создание экземпляра до первого использования локали.
const cache = new Map();
function getGlobalize(locale) {
let instance = cache.get(locale);
if (!instance) {
instance = new Globalize(locale);
cache.set(locale, instance);
}
return instance;
}
Такой подход особенно эффективен при:
В серверной среде кеш экземпляров становится глобальным для процесса. Это создаёт дополнительные особенности:
Пример глобального кеша:
const globalCache = new Map();
export function getGlobalize(locale) {
if (!globalCache.has(locale)) {
globalCache.set(locale, new Globalize(locale));
}
return globalCache.get(locale);
}
При работе с большим числом локалей (например, пользовательский контент, мультиарендные системы) необходимо ограничивать размер кеша.
Один из вариантов — LRU-подход:
class LRUCache {
constructor(lim it = 50) {
this.limit = limit;
this.map = new Map();
}
get(key) {
if (!this.map.has(key)) return null;
const value = this.map.get(key);
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(100);
Такой подход обеспечивает:
В сложных системах кеширование может разделяться на уровни:
Используется во всём приложении для базовых локалей.
Применяется внутри конкретного сервиса (например, биллинга или аналитики).
Используется в рамках одного HTTP-запроса для предотвращения повторных обращений.
function createRequestContext(locale) {
const cache = new Map();
return {
getGlobalize() {
if (!cache.has(locale)) {
cache.set(locale, new Globalize(locale));
}
return cache.get(locale);
}
};
}
При корректной реализации кеширование экземпляров даёт:
Основной эффект проявляется в системах, где форматирование выполняется часто:
Типовые проблемы:
Использование только локали без учёта модулей приводит к некорректным форматам.
При динамических локалях кеш может расти бесконечно.
Если CLDR данные загружаются асинхронно, экземпляр может оказаться невалидным.
Каждый воркер должен иметь собственный кеш, иначе возникает дублирование или гонки инициализации.
Для серверных приложений применяется предварительное создание наиболее популярных локалей:
const popularLocales = ["en", "ru", "de", "fr"];
popularLocales.forEach(locale => {
cache.set(locale, new Globalize(locale));
});
Это уменьшает задержки первого запроса для пользователей из основных регионов.
Часто имеет смысл кешировать не только экземпляр Globalize, но и производные функции:
const formattersCache = new Map();
function getNumberFormatter(locale) {
if (!formattersCache.has(locale)) {
const g = getGlobalize(locale);
formattersCache.set(locale, g.numberFormatter());
}
return formattersCache.get(locale);
}
Такой подход снижает стоимость вызова форматирования до минимального уровня, устраняя даже накладные расходы на доступ к методам экземпляра.