Как обновлять интерфейс на управляемой форме 1С во время выполнения длительной операции?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

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

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

Причина проблемы: модальность серверных вызовов

В архитектуре управляемых форм клиент (интерфейс) и сервер (обработка данных) работают раздельно. Когда вы с клиентской формы вызываете серверную процедуру, вызов является модальным. Это означает, что клиент будет ждать, пока сервер полностью не завершит свою работу. Если на сервере запущен цикл по обработке тысячи контрагентов, клиент будет «заморожен» всё это время. Платформа не позволяет серверному коду напрямую управлять элементами формы на клиенте в середине своего выполнения.

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

Решение 1: Порционная обработка с обработчиком ожидания (простой способ для новичков)

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

Рассмотрим по шагам алгоритм реализации:

  1. Подготовка данных на клиенте. Перед началом обработки получаем на клиенте массив данных, которые нужно обработать (например, массив ссылок на контрагентов). Этот массив будем хранить в реквизите формы.
  2. Создание серверной процедуры для обработки одной порции. Эта процедура должна принимать на вход не весь массив, а только его часть (порцию). Например, 10-20 элементов. Внутри она обрабатывает эти элементы и возвращает результат или просто завершает работу.
    
    &НаСервере
    Процедура ОбработатьПорциюКонтрагентов(ПорцияДанных)
        Для каждого Элемент Из ПорцияДанных Цикл
            // Получаем объект, изменяем, записываем
            ОбъектКонтрагента = Элемент.ПолучитьОбъект();
            ОбъектКонтрагента.Комментарий = "Обработан " + ТекущаяДата();
            ОбъектКонтрагента.Записать();
        КонецЦикла;
    КонецПроцедуры
    
  3. Запуск обработки с клиента. Создаем клиентскую процедуру, которая будет управлять процессом. Она берет первую порцию из общего массива, отправляет ее на сервер, а затем подключает обработчик ожидания для запуска следующего шага.
  4. Использование обработчика ожидания. Метод ПодключитьОбработчикОжидания() позволяет вызвать определенную клиентскую процедуру через заданный интервал времени (например, 0.1 секунды) всего один раз. В этой процедуре мы будем проверять, остались ли еще данные для обработки.
    
    &НаКлиенте
    Процедура ВыполнитьОбработку()
        // ... здесь код подготовки массива данных для обработки ...
            
        // Запускаем первый шаг
        ОбработатьСледующуюПорцию();
    КонецПроцедуры
    
    &НаКлиенте
    Процедура ОбработатьСледующуюПорцию()
            
        // Определяем, есть ли еще что обрабатывать
        Если ДанныеДляОбработки.Количество() > 0 Тогда
                
            // Берем порцию, например, 10 элементов
            Порция = Новый Массив;
            Для сч = 1 по Мин(10, ДанныеДляОбработки.Количество()) Цикл
                Порция.Добавить(ДанныеДляОбработки[0]);
                ДанныеДляОбработки.Удалить(0);
            КонецЦикла;
                
            // Вызываем сервер для обработки порции
            ОбработатьПорциюКонтрагентов(Порция);
                
            // Обновляем элементы формы, например, список
            Элементы.СписокКонтрагентов.Обновить();
                
            // Планируем вызов следующей порции
            ПодключитьОбработчикОжидания("ОбработатьСледующуюПорцию", 0.1, Истина);
                
        Иначе
            Сообщить("Обработка завершена!");
        КонецЕсли;
            
    КонецПроцедуры
    

    Важный момент: в обработчике ожидания третий параметр (Однократно) установлен в Истина. Это значит, что после выполнения он сам отключится. Мы снова его подключаем внутри процедуры, пока есть что обрабатывать. Если бы мы хотели постоянный вызов, мы бы подключили его один раз в начале с параметром Ложь, а в конце вызвали бы ОтключитьОбработчикОжидания().

Плюсы метода:

Минусы метода:

Решение 2: Фоновые задания и Библиотека стандартных подсистем (БСП)

Это стандартный и наиболее правильный с точки зрения архитектуры 1С подход для реализации длительных операций. Он предполагает запуск обработки в отдельном сеансе — фоновом задании. Пользовательский интерфейс при этом не блокируется, и пользователь может продолжать работать в программе.

Вручную управлять фоновыми заданиями довольно сложно. К счастью, в Библиотеке стандартных подсистем (БСП) есть готовый механизм ДлительныеОперации, который сильно упрощает этот процесс.

Общая схема работы с ДлительныеОперации:

  1. Подготовка экспортной процедуры. Логика обработки выносится в отдельную экспортную процедуру общего модуля (с флагами «Сервер» и «Внешнее соединение»). Эта процедура принимает структуру с параметрами и адрес временного хранилища для результата. Внутри процедуры нужно периодически вызывать ДлительныеОперации.СообщитьПрогресс(), чтобы обновлять статус выполнения.
  2. Запуск фоновой операции. На клиенте вызывается функция ДлительныеОперации.ВыполнитьВФоне(). В нее передается имя процедуры для выполнения и параметры. Функция запускает фоновое задание и возвращает структуру, содержащую адрес результата и идентификатор задания.
  3. Ожидание и обновление интерфейса. На форме с помощью ПодключитьОбработчикОжидания запускается периодический опрос состояния фонового задания. Для этого используется функция ДлительныеОперации.ПолучитьСтатус(). Когда задание завершено, обработчик ожидания получает результат, отключается и обновляет данные на форме. БСП также предоставляет готовую форму отображения состояния, которую можно использовать.

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

Плюсы метода:

Минусы метода:

Решение 3: Система взаимодействия (современный подход)

Более новый и гибкий механизм, который появился в последних версиях платформы. Система взаимодействия — это, по сути, встроенный мессенджер, который позволяет разным сеансам 1С обмениваться сообщениями.

Сценарий использования такой:

  1. Клиентский сеанс запускает фоновое задание.
  2. Фоновое задание в процессе своей работы (например, после обработки каждого контрагента) отправляет сообщение через Систему взаимодействия конкретному пользователю.
  3. Клиентский сеанс этого пользователя подписан на получение сообщений и, как только сообщение приходит, срабатывает обработчик, который обновляет интерфейс (прогресс-бар, таблицу и т.д.).

Этот подход реализует механизм коллбэков (callbacks), когда сервер сам инициирует обновление на клиенте, а не клиент постоянно опрашивает сервер. Это наиболее эффективно, но и наиболее сложно в настройке, так как требует развернутого и настроенного сервера взаимодействия.

Плюсы метода:

Минусы метода:

Итог: какой способ выбрать?

Выбор метода зависит от сложности задачи и вашего опыта:

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

← На главную