Международный API JavaScript (Intl) обеспечивает форматирование дат, чисел, валют, сортировку строк и разбиение текста с учётом локали. За внешней простотой скрывается слой ICU-данных и механизмов выбора локали, который влияет на производительность как при инициализации, так и при выполнении операций форматирования.
Ключевые источники затрат:
Разрешение локали (locale resolution) При создании форматтеров происходит анализ списка локалей, выбор наиболее подходящей и загрузка соответствующих правил форматирования. В средах с большим количеством поддерживаемых локалей эта операция становится заметной при частом создании экземпляров.
Инициализация ICU структур Каждый форматтер
(Intl.NumberFormat, Intl.DateTimeFormat,
Intl.Collator, Intl.Segmenter) создаёт
внутренние структуры ICU. Они включают таблицы правил, шаблоны
форматирования и предрасчитанные данные.
Аллокации объектов Создание каждого нового форматтера сопровождается выделением памяти. При высокочастотных вызовах это приводит к росту нагрузки на GC.
Форматирование как отдельная операция Хотя сам вызов
format() относительно дешёв, его стоимость зависит от
сложности локали, количества опций и типа данных.
Профилирование локализованного кода строится на сопоставлении затрат создания и повторного использования форматтеров.
Performance API
Используется для измерения микрозадержек:
performance.now() — измерение времени создания и
форматированияperformance.mark() и performance.measure()
— структурирование тестовNode.js профилирование
node --prof и --prof-process для анализа
hot pathconsole.profile() для Chrome DevToolsChrome DevTools Performance
Позволяет увидеть:
Создание форматтера — одна из наиболее дорогостоящих операций в Intl API.
const nf = new Intl.NumberFormat('ru-RU', {
style: 'currency',
currency: 'RUB'
});
Внутри выполняется:
При массовом создании (например, в цикле рендера) наблюдается линейное ухудшение производительности.
const dtf = new Intl.DateTimeFormat('en-US', {
dateStyle: 'full',
timeStyle: 'long'
});
Затраты включают:
Особенно дорогостоящи опции dateStyle и
timeStyle, так как они разворачиваются в набор
детализированных правил.
const collator = new Intl.Collator('de', {
sensitivity: 'base'
});
Создание включает:
Collator особенно тяжёл при использовании сложных локалей с диакритикой и нестандартными правилами сортировки.
const segmenter = new Intl.Segmenter('ja', { granularity: 'grapheme' });
Наиболее затратный из базовых компонентов Intl:
Основной принцип производительного кода с Intl заключается в разделении создания и использования.
const formatters = {
ruCurrency: new Intl.NumberFormat('ru-RU', {
style: 'currency',
currency: 'RUB'
})
};
function formatPrice(value) {
return formatters.ruCurrency.format(value);
}
Ключевая особенность: экземпляры форматтеров являются неизменяемыми и потокобезопасными в рамках JS-движка.
let dtf;
function formatDate(date) {
if (!dtf) {
dtf = new Intl.DateTimeFormat('ru-RU', {
dateStyle: 'medium'
});
}
return dtf.format(date);
}
Подход уменьшает стартовую стоимость приложения, перенося её на первый вызов.
const cache = new Map();
function getNumberFormat(locale) {
if (!cache.has(locale)) {
cache.set(locale, new Intl.NumberFormat(locale));
}
return cache.get(locale);
}
При мультилингвальных системах это предотвращает экспоненциальный рост числа объектов.
Intl становится критическим фактором производительности при использовании внутри:
items.map(item =>
new Intl.NumberFormat('ru-RU').format(item.price)
);
Каждая итерация создаёт новый форматтер, что приводит к:
const nf = new Intl.NumberFormat('ru-RU');
items.map(item => nf.format(item.price));
При поддержке множества локалей важно учитывать:
Механизм fallback (например, fr-CA → fr → en) добавляет
дополнительную стоимость при инициализации.
В высоконагруженных системах Intl часто становится финальным этапом обработки данных:
Профилирование показывает, что перенос Intl внутрь бизнес-логики приводит к скрытым затратам, особенно при повторных вызовах.
Производительность Intl зависит от:
Сокращённые ICU-сборки уменьшают память, но увеличивают стоимость fallback-обработки и ограничивают локали.
Основные показатели:
Дополнительно:
Intl.DateTimeFormat при каждом рендере
компонентаIntl.NumberFormat без кеширования в
таблицахIntl.Collator внутри цикловIntl.SegmenterЭти сценарии особенно заметны в интерфейсах с частыми обновлениями состояния.
Прогрев позволяет снизить задержки первого использования:
new Intl.NumberFormat('ru-RU').format(0);
new Intl.DateTimeFormat('ru-RU').format(Date.now());
Такой подход переносит стоимость инициализации из критического пути выполнения.
На сервере Intl ведёт себя иначе:
В SSR-сценариях кеширование форматтеров часто становится обязательным условием стабильной латентности.
При анализе flamegraph’ов Intl-операции обычно проявляются как:
Основная цель профилирования — отделить стоимость инициализации от стоимости использования и устранить дублирование создания объектов в горячих путях выполнения.