Измерение производительности в библиотеках интернационализации требует учета нескольких уровней: загрузка данных CLDR, инициализация Globalize, время выполнения форматирования и влияние кэширования. Неправильная методика приводит к ложным выводам, особенно при разовых измерениях, где значительную долю времени занимает холодный старт движка JavaScript.
Корректный подход опирается на разделение этапов:
Использование performance.now() обеспечивает достаточную
точность для микробенчмарков в браузере и Node.js.
const t0 = performance.now();
Globalize.formatNumber(1234567.89);
const t1 = performance.now();
console.log("time:", t1 - t0);
Однако единичные измерения не отражают реальную картину, поэтому применяется цикл прогрева:
for (let i = 0; i < 1000; i++) {
Globalize.formatNumber(i);
}
После прогрева фиксируется стабильное состояние JIT-компиляции и кэширования внутренних структур.
Globalize основан на данных CLDR и не содержит встроенной локализационной логики. Это означает, что производительность напрямую зависит от:
Каждый вызов форматирования может задействовать несколько уровней поиска правил локали, особенно при работе с числовыми форматами и сообщениями ICU.
Ключевая особенность — отсутствие «магии» в рантайме: библиотека делает строго то, что определено данными CLDR, поэтому узкие места легко локализуются профилировщиком.
Загрузка CLDR представляет собой одну из наиболее затратных фаз. Данные обычно подключаются вручную:
Globalize.load(
require("cldr-data/main/ru/numbers"),
require("cldr-data/supplemental/likelySubtags")
);
Основные источники задержек:
const start = performance.now();
Globalize.load(
require("cldr-data/main/ru"),
require("cldr-data/supplemental/likelySubtags")
);
const end = performance.now();
console.log("CLDR load:", end - start);
При анализе важно учитывать, что первый require может
быть значительно медленнее из-за дискового I/O и кэширования модуля
Node.js.
Форматирование чисел — одна из самых частых операций. В Globalize оно включает разбор шаблонов CLDR, применение правил группировки и округления.
const numberFormatter = Globalize.numberFormatter();
const start = performance.now();
for (let i = 0; i < 100000; i++) {
numberFormatter(i + 0.123);
}
const end = performance.now();
console.log("numbers:", end - start);
Повторное создание formatter внутри цикла резко ухудшает результаты:
// антипаттерн
for (let i = 0; i < 100000; i++) {
Globalize.numberFormatter()(i);
}
Форматирование дат включает обработку календарных правил, временных зон и локалей.
const dateFormatter = Globalize.dateFormatter({ datetime: "medium" });
const start = performance.now();
for (let i = 0; i < 100000; i++) {
dateFormatter(new Date(2020, 0, 1 + (i % 30)));
}
const end = performance.now();
console.log("dates:", end - start);
Date в внутреннее представление;Особенно заметна разница между форматами short,
medium, long, где более длинные форматы
требуют больше операций подстановки.
Форматирование сообщений — наиболее сложный слой Globalize, так как включает интерполяцию и правила множественного числа.
const messageFormatter = Globalize.messageFormatter(
"{count, plural, one {# файл} few {# файла} many {# файлов}}"
);
const start = performance.now();
for (let i = 0; i < 100000; i++) {
messageFormatter({ count: i });
}
const end = performance.now();
console.log("messages:", end - start);
Ключевой фактор производительности — переиспользование скомпилированных formatter-ов.
Globalize активно полагается на кэширование форматеров. При правильной архитектуре приложения:
Эффект кэширования может давать разницу в порядках величин.
Сравнение:
// медленно
for (let i = 0; i < 10000; i++) {
Globalize.numberFormatter()(i);
}
// быстро
const f = Globalize.numberFormatter();
for (let i = 0; i < 10000; i++) {
f(i);
}
Микробенчмарки в JavaScript подвержены влиянию:
Для повышения достоверности применяются:
function bench(fn, name) {
const runs = 10;
let total = 0;
for (let r = 0; r < runs; r++) {
const start = performance.now();
for (let i = 0; i < 100000; i++) fn(i);
total += performance.now() - start;
}
console.log(name, total / runs);
}
Встроенный Intl в современных движках часто работает
быстрее за счет нативной реализации.
Сравнение проводится по одинаковым сценариям:
Globalize уступает в raw-speed, но выигрывает в предсказуемости и независимости от среды выполнения.
Основные причины различий:
Производительность нельзя оценивать только по времени выполнения. Globalize может создавать значительные объемы промежуточных объектов.
Типичные источники потребления памяти:
Инструменты анализа:
--inspect;Особое внимание уделяется утечкам через:
CLDR-данные существенно влияют на размер приложения. В production-сборках важно учитывать:
Анализ проводится через:
Рост размера бандла напрямую влияет на:
Практические проблемы производительности обычно возникают не в самой библиотеке, а в интеграции:
Наиболее критичный паттерн:
// дорого
function render(value) {
return Globalize.numberFormatter()(value);
}
Оптимальный вариант:
const formatter = Globalize.numberFormatter();
function render(value) {
return formatter(value);
}
Результаты профилирования обычно приводят к нескольким оптимизациям:
Профилирование показывает, что основная стоимость Globalize сосредоточена не в вычислениях, а в управлении данными и объектами JavaScript, что делает архитектурные решения более значимыми, чем микрооптимизации отдельных вызовов форматирования.