Центр событий: точечные обновления без лишних перерисовок
Live-лента получает больше событий, чем пользователю нужно видеть как отдельные кадры. Разбираем нормализованный store, подписки по entity id и коалесцирование обновлений, чтобы интерфейс оставался быстрым.

Поток данных быстрее глаза пользователя
Live-center может получать больше изменений, чем имеет смысл рисовать отдельными commit. Клиенту нужна правильная последняя версия, но не обязательно отдельный render для каждого промежуточного тика.
Нормализованное хранилище и точечные подписки
События, рынки и selections хранятся по id. Карточка подписывается только на сущности, которые отображает. Stream handler меняет store, а UI scheduler коалесцирует обновления до ближайшего кадра. Это снижает площадь перерисовки.
Мемоизация не лечит неправильную модель
Если каждый delta создаёт новый огромный объект страницы, memo-компоненты всё равно будут получать изменившиеся ссылки. Сначала нормализуется состояние и гранулярность подписки, потом добавляется memoization.
Видимость как сигнал приоритета
Карточки за пределами viewport могут получать store updates, но их визуальный commit можно отложить. При возвращении в область видимости компонент читает текущий snapshot, а не проигрывает очередь старых анимаций.
Неправильный ключ создаёт «чужую цену»
При переиспользовании элемента списка React/Vue key должен идентифицировать сущность, а не позицию. Иначе локальные transitions и подписки могут остаться от предыдущего рынка. Это особенно заметно при сортировке live-листа.
Где обычно теряется производительность
Проблема live-center редко начинается с одного тяжёлого компонента. Чаще каждое обновление затрагивает слишком большой участок дерева: меняется общий объект event, пересчитываются коллекции, пересоздаются props и десятки карточек получают новый render даже без визуального изменения.
Нормализованный store и подписки по entity id уменьшают этот радиус. Дополнительно стоит отделить скорость входящего потока от частоты paint: несколько дельт за один кадр можно свести к последнему актуальному состоянию. Пользователь увидит свежий результат, а браузер не будет отрисовывать промежуточные версии, которые всё равно невозможно различить.
- Профилировать не только render time, но и количество затронутых компонентов на одно обновление.
- Приоритизировать карточки в viewport и снижать частоту для невидимых секций.
- Не использовать индекс массива как key в списке событий, которые меняют порядок.
Бюджет рендера задаётся от видимого экрана
Если в live-center одновременно идёт двадцать матчей, не все карточки требуют одинаковой частоты paint. Карточка в viewport с меняющимся счётом должна обновиться быстро; блок внизу страницы может получить тот же актуальный snapshot, но визуально применить его позже. Это не потеря данных, а разделение state freshness и render cadence.
Такой подход работает только при нормализованном store и устойчивых ключах. LiveCenter подписывается на конкретные entity, а не на весь массив событий. При возвращении карточки в viewport она читает последнюю версию, поэтому нет необходимости воспроизводить каждый пропущенный delta.
В профилировщике стоит искать путь stream message → store update → component commit → paint. Если дорого стоит уже первый шаг, memoization React-компонентов проблему не решит; если дорого второй — надо смотреть fan-out подписок и структуру state.
Профилировать участок «поток → отрисовка»
Серверный lag и frontend lag различаются. В клиентской телеметрии полезно отдельно измерять received_at→store_applied и store_applied→paint для sampled sessions. Тогда видно, где теряется актуальность.

Связанные разборы по той же архитектурной цепочке
Состояние спортивного события: счёт, фазы и завершение матча
Как связать счёт, таймер и фазы матча в модель состояний, обрабатывать поздние сообщения поставщика и не допускать невозможных переходов.
Перейти к разбору →ИнтерфейсыПоиск по событиям и рынкам: отдельный индекс чтения
Зачем спортивной платформе отдельный поисковый индекс, как обновлять его из каталога событий и что делать с устаревшими результатами поиска.
Перейти к разбору →НадёжностьСессия пользователя и публичный кэш: где проходит граница
Как отделить публичную страницу события от данных аккаунта, сохранить эффективность кэша и не допустить персональные данные в общий ответ.
Перейти к разбору →Букмекерская логикаКнопка коэффициента: доступность, изменение цены и приостановка
Как проектировать кнопку коэффициента: изменение цены, приостановка, фокус, клавиатурное управление и понятные состояния после выбора пользователя.
Перейти к разбору →