Программное обновление

Программное обновление в Unpoly

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

Базовая функция: up.render(). Она принимает селектор целевого фрагмента и параметры обновления. По умолчанию Unpoly загрузит новый HTML с сервера, заменит содержимое указанного слоя и выполнит необходимые переходы и анимацию.

up.render('.content', { url: '/articles/42' })

Сервер должен вернуть частичный HTML, подходящий для замены выбранного фрагмента. Если селектор не найден в возвращённом документе, поведение можно настраивать с помощью опций failTarget, fallback и других.

Специфика целевых слоёв

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

up.render({ target: '.content', layer: 'root', url: '/dashboard' })

Ключевой момент: отсутствие указания layer подчиняется стандартной стратегии — обновление происходит в активном слое. Также возможна работа с новым слоем (например, модальным):

up.layer.open({ url: '/edit/42', target: '.modal-content' })

Параметры запроса и настройки поведения

Программное обновление поддерживает те же параметры, что и атрибуты ссылок/форм:

  • url — путь к ресурсу
  • method — HTTP-метод, по умолчанию GET
  • params — дополнительные данные запроса
  • headers — заголовки
  • timeout — время ожидания
  • history — управление историей браузера
  • scroll — поведение скролла
  • focus — стратегия фокуса
up.render('.list', {
  url: '/items',
  params: { page: 3 },
  history: true,
  scroll: 'preserve'
})

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

Переходы и анимации при программном обновлении

Разметка и код могут задавать переходы (transition) для плавной смены содержимого. При программном вызове переход задаётся параметром:

up.render('.panel', {
  url: '/panel/info',
  transition: 'cross-fade'
})

Если фрагмент имеет в HTML атрибут up-transition, он будет использован по умолчанию. Анимации учитывают слои, поддерживают отмену и взаимное перекрытие обновлений.

Конкурирующие обновления

Unpoly отменяет предыдущие запросы при появлении новых, если они направлены на тот же слой. Это предотвращает состязательные состояния и упрощает управление UI. При необходимости стратегию можно изменить параметрами abort, queue и abortable.

up.render('.feed', { url: '/feed?since=2000', abort: false })

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

Программное обновление без запроса к серверу

Unpoly умеет менять слой локально. Вызов up.replace() позволяет заменить целевой фрагмент переданным HTML:

up.replace('.title', '<h1>Новое заглавие</h1>')

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

Локальные фрагменты и совместная загрузка

Unpoly поддерживает механизм fragments, позволяющий запросить с сервера только конкретные части документа. Программный вызов позволяет указать массив целей:

up.render({
  url: '/stats',
  target: ['.chart', '.summary']
})

Ответ сервера должен содержать оба фрагмента; иначе применяется стратегия восстановления (fallback), например обновление корневого слоя.

Работа с историей программно

Если обновление подменяет значимую часть страницы, часто требуется управление history. Пример:

up.render('.main', {
  url: '/products?page=4',
  history: true
})

Unpoly вставит новую запись в историю браузера и обеспечит корректную работу кнопок Back/Forward. Также доступно history: 'replace' для замены текущей записи.

Обработка ошибок

Ошибки сетевого слоя или несовпадение фрагментов не приводят к аварийному падению интерфейса. Возможные стратегии:

  • failTarget — целевой фрагмент, который обновится при ошибке
  • fallback — переход к полному обновлению слоя или страницы
  • onError — хук для программного перехвата
up.render('.dashboard', {
  url: '/dashboard',
  failTarget: '.error-box'
})

Сервер может вернуть только фрагмент ошибки, а клиент покажет его согласно стратегии.

Интеграция с формами и пользовательскими событиями

Формы можно отправлять программно:

up.submit('.edit-form')

или использовать up.render() с параметром method: 'POST'. Это позволяет встраивать Unpoly в сложное клиентское окружение, например, отправку по горячим клавишам или комбинацию с кастомными контролами.

Работа с сокетами и реактивными источниками

При обновлении UI по внешним данным (WebSocket, SSE, таймер) стандартная схема:

  1. По событию выполнить up.render() или up.replace()
  2. Передать локальные данные через params или встроить в HTML при локальной замене
  3. При необходимости обновить несколько фрагментов за один запрос

Это позволяет синхронизировать UI без ручного управления состояниями.

Хуки и жизненный цикл фрагментов

Unpoly предоставляет хуки для инициализации и разрушения фрагментов: up.compiler, up.validator, up.destructor. Программное обновление вызывает их автоматически, обеспечивая предсказуемый жизненный цикл элементов:

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

Производительность и оптимизация

Лучшей практикой считается маленький размер частичных HTML и фрагментов. Программное обновление позволяет загружать только конкретные области, снижая трафик и нагрузку на сервер. Кэширование (up.cache) может хранить ответы и переиспользовать их при следующих вызовах up.render().

Итеративные обновления и прогресс-индикаторы

При длительных операциях можно включить индикатор запросов (up.progress) или задать собственную стратегию. Это помогает избежать ощущения блокировки при работе со сложными слоями и несколькими запросами.

Связывание с архитектурой приложения

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