Кеширование результатов

Кэширование в Globalize опирается на несколько уровней оптимизации: предварительную загрузку CLDR-данных, переиспользование скомпилированных форматтеров и внутреннее сохранение результатов разбора и форматирования. Такой подход позволяет существенно снизить стоимость повторяющихся операций интернационализации, особенно в приложениях с интенсивным UI-рендерингом и частыми обновлениями данных.

Основой работы библиотеки является CLDR (Unicode Common Locale Data Repository). Данные локали загружаются один раз и сохраняются в памяти. После подключения набора данных для конкретной локали повторные обращения к тем же структурам не требуют повторного парсинга JSON или обращения к источнику данных.

Типичный сценарий:

  • загрузка глобальных данных CLDR;
  • загрузка данных конкретной локали (например, ru, en, de);
  • использование этих данных всеми форматтерами без повторного чтения.

Внутри системы CLDR фактически превращается в неизменяемую структуру, что позволяет использовать её как кэш-слой первого уровня. Любые операции форматирования чисел, дат и сообщений опираются именно на этот слой.

Кэширование форматтеров

Наиболее важный механизм оптимизации связан с тем, что создание форматтера — дорогая операция. При каждом вызове форматирования даты, числа или валюты происходит компиляция функции форматирования, которая учитывает локаль, параметры и правила CLDR.

Примерные типы форматтеров:

  • форматтер чисел (number formatter);
  • форматтер валют;
  • форматтер дат и времени;
  • форматтер относительного времени.

После первого создания форматтера он сохраняется и повторно используется при идентичных параметрах.

Ключ кэширования формируется из комбинации:

  • локаль (locale);
  • тип форматирования;
  • набор опций (precision, style, currency и т.д.).

Таким образом, вызов с одинаковыми параметрами не приводит к повторной компиляции логики форматирования.

Внутреннее переиспользование функций

Каждый форматтер в Globalize фактически является скомпилированной функцией. При повторном запросе форматтера с теми же параметрами библиотека возвращает уже существующую функцию, а не создает новую.

Это особенно важно для высоконагруженных интерфейсов:

  • таблицы с динамическими значениями;
  • дашборды с обновлением в реальном времени;
  • виртуальные списки.

Без кэширования каждое обновление строки приводило бы к повторной генерации форматтера, что резко увеличивало бы нагрузку на GC и CPU.

Кэширование сообщений (MessageFormatter)

Отдельный уровень кэширования относится к шаблонам сообщений. При использовании ICU-подобного синтаксиса сообщения компилируются в функции, которые затем многократно вызываются.

Процесс выглядит следующим образом:

  1. строка шаблона анализируется;
  2. строится AST (абстрактное синтаксическое дерево);
  3. создаётся функция форматирования;
  4. результат сохраняется в кэше.

При повторном использовании идентичного шаблона компиляция пропускается.

Особенность этого механизма заключается в том, что ключ кэша зависит не только от текста сообщения, но и от локали, так как правила плюрализации и форматирования зависят от языка.

Кэширование чисел, дат и валют

Форматирование базовых типов данных также использует промежуточное кэширование.

Числа

Форматтер чисел сохраняется для комбинаций:

  • стиль отображения (decimal, percent, scientific);
  • количество знаков после запятой;
  • локаль.

Повторное использование форматтера позволяет избежать повторного вычисления правил округления и разделителей.

Даты

Форматирование дат включает:

  • локализацию названий месяцев и дней недели;
  • правила порядка компонентов даты;
  • формат времени.

Так как эти параметры зависят от локали, кэширование позволяет избежать повторной интерпретации календарных правил.

Валюты

Для валют ключ кэша включает:

  • код валюты;
  • стиль отображения (symbol, code, name);
  • локаль.

Поскольку валютные правила относительно стабильны, кэширование особенно эффективно при массовом рендеринге финансовых интерфейсов.

Стратегия «компиляция один раз — использование многократно»

Внутренняя архитектура Globalize ориентирована на модель, где любая сложная операция сначала компилируется в функцию, а затем многократно используется без повторных затрат.

Этот принцип применяется ко всем основным компонентам:

  • форматтеры;
  • парсеры;
  • message functions.

Такой подход снижает стоимость интернационализации до уровня вызова обычной функции JavaScript после первичной инициализации.

Мемоизация на уровне параметров

Кэширование в библиотеке по сути реализует форму мемоизации, где ключом выступает сериализованная конфигурация вызова.

Типичный набор параметров:

  • locale;
  • options object;
  • message string.

Важно, что объекты параметров нормализуются, иначе кэш терял бы эффективность из-за различий в ссылках на объекты с одинаковым содержимым.

Управление памятью и компромиссы

Кэширование в интернационализационных библиотеках всегда связано с балансом между производительностью и потреблением памяти.

Основные особенности:

  • рост числа локалей увеличивает размер кэша;
  • большое количество уникальных опций приводит к разрастанию пула форматтеров;
  • долгоживущие приложения могут накапливать значительное количество скомпилированных функций.

Поэтому в архитектуре Globalize кэширование ограничивается только действительно повторно используемыми сущностями, без агрессивного сохранения промежуточных вычислений.

Повторное использование в SPA и UI-фреймворках

В одностраничных приложениях кэширование играет ключевую роль:

  • при первом рендере создаются все необходимые форматтеры;
  • далее они переиспользуются во всех компонентах;
  • переключение состояния UI не вызывает повторной компиляции.

Это особенно важно для React-, Vue- и Angular-приложений, где рендеринг может происходить десятки раз в секунду.

Оптимизация горячих путей

Наиболее частые операции:

  • форматирование чисел в таблицах;
  • отображение дат в списках;
  • рендеринг валютных значений.

Все они попадают в «горячий путь», где кэширование даёт максимальный эффект. В таких сценариях повторное использование форматтеров уменьшает количество аллокаций и снижает давление на garbage collector.

Косвенное кэширование через замыкания

Скомпилированные функции форматирования в Globalize используют замыкания, внутри которых фиксируются:

  • локаль;
  • правила форматирования;
  • предрассчитанные таблицы CLDR.

Таким образом, часть вычислений переносится из runtime в момент компиляции, а дальнейшие вызовы становятся максимально лёгкими.

Стабильность кэша при изменении локали

При смене локали кэш ведёт себя как набор независимых пространств:

  • форматтеры для одной локали не пересекаются с другой;
  • данные CLDR для разных языков изолированы;
  • переключение локали приводит к обращению к другому набору кэшированных функций.

Это позволяет безопасно поддерживать мультиязычные интерфейсы без риска смешивания правил форматирования.

Кэширование и производительность масштабных приложений

В приложениях с большим количеством данных эффективность кэширования проявляется особенно явно:

  • снижение времени рендеринга списков;
  • уменьшение количества вычислений при обновлениях состояния;
  • стабильная нагрузка на CPU при росте объёма данных.

Основной выигрыш достигается за счёт того, что стоимость создания форматтера переносится в редкий этап инициализации, а не в частые операции отображения.