При разработке на управляемых формах программисты часто сталкиваются с проблемой: выполнение длительной операции на сервере «замораживает» интерфейс пользователя. Пользователь не видит, сколько времени осталось до конца процесса, и может решить, что программа зависла. Попытки вызвать стандартную команду Состояние() внутри серверного цикла не приносят результата, так как этот метод работает исключительно на клиенте. Разберем подробно, как правильно организовать визуализацию процесса выполнения задачи.
Прежде чем приступать к написанию кода, подготовим визуальную часть. В 1С:Предприятие 8.3 для отображения прогресса не нужно использовать сторонние компоненты. Достаточно стандартных средств платформы (хотя в некоторых случаях может потребоваться индикатор прогресса в ячейке динамического списка). Проанализируем шаги по настройке формы:
ПрогрессВыполнения. Установим тип данных — Число (длина 3, точность 0).Теперь, когда мы будем менять значение реквизита ПрогрессВыполнения на клиенте, полоска индикатора будет автоматически заполняться.
Этот метод является самым простым для понимания и реализации, если вы не хотите использовать фоновые задания. Идея заключается в том, чтобы разделить одну большую задачу на много маленьких порций. Рассмотрим этот процесс по шагам:
Сначала подготовим данные на сервере (например, соберем массив ссылок объектов, которые нужно обработать) и вернем их на клиент. Затем на клиенте запустим цикл, который будет вызывать сервер для обработки каждой порции отдельно.
&НаКлиенте
Процедура ВыполнитьОбработку(Команда)
// Получаем массив объектов для обработки
ДанныеДляОбработки = ПодготовитьДанныеНаСервере();
ВсегоОбъектов = ДанныеДляОбработки.Количество();
Если ВсегоОбъектов = 0 Тогда
Возврат;
КонецЕсли;
// Настраиваем начальные значения индикатора
Объект.ПрогрессВыполнения = 0;
// Запускаем цикл обработки порциями
Для Итерация = 0 По ВсегоОбъектов - 1 Цикл
ОбработатьОбъектНаСервере(ДанныеДляОбработки[Итерация]);
// Обновляем индикатор
Объект.ПрогрессВыполнения = (Итерация + 1) / ВсегоОбъектов * 100;
// Принудительно обновляем интерфейс (для тонкого клиента)
ОбработкаПрерыванияПользователя();
КонецЦикла;
ПоказатьПредупреждение(, "Обработка завершена!");
КонецПроцедуры
Важный нюанс: Этот способ хорошо работает в файловых базах, но в клиент-серверном варианте частые вызовы сервера (ping-pong между клиентом и сервером) могут замедлить общую скорость выполнения. Поэтому рекомендуется обрабатывать объекты не по одному, а пачками (например, по 100 штук за один вызов сервера).
Для более тяжелых операций правильнее использовать Фоновые задания. Это позволяет серверу выполнять задачу в отдельном потоке, а клиенту лишь периодически «спрашивать» сервер о текущем статусе. Выясним, как передать прогресс из фонового задания на форму.
Поскольку фоновое задание не имеет доступа к форме, мы будем использовать ПоместитьВоВременноеХранилище(). Разберем алгоритм:
Пример кода для серверной части (в модуле объекта или общем модуле):
Процедура ДлительнаяОперацияНаСервере(АдресХранилища, Параметры) Экспорт
Выборка = СформироватьВыборку(Параметры);
Всего = Выборка.Количество();
Счетчик = 0;
Пока Выборка.Следующий() Цикл
// Основная логика обработки
ОбработатьДанные(Выборка.Ссылка);
Счетчик = Счетчик + 1;
Процент = (Счетчик / Всего) * 100;
// Передаем прогресс через хранилище
ПоместитьВоВременноеХранилище(Процент, АдресХранилища);
КонецЦикла;
КонецПроцедуры
На стороне клиента нам понадобится метод ПодключитьОбработчикОжидания(), который будет обращаться к функции, проверяющей состояние хранилища и обновляющей реквизит Объект.ПрогрессВыполнения.
Если ваша конфигурация построена на базе БСП (что актуально для большинства современных решений, таких как УТ 11, БП 3.0, ERP), мы крайне рекомендуем использовать стандартную подсистему «Длительные операции». Это наиболее стабильный и «красивый» способ.
Проанализируем работу с общим модулем ДлительныеОперации. Для этого в серверном коде, который выполняется в фоне, необходимо вызывать метод СообщитьПрогресс():
// Код на сервере внутри фонового задания
Процедура ВыполнитьДействие() Экспорт
// ... какой-то цикл ...
ДлительныеОперации.СообщитьПрогресс(ТекущийПроцент, "Обработка документов...");
КонецПроцедуры
На клиенте запуск и отслеживание выглядят очень лаконично благодаря методу ОжидатьЗавершение(). Система сама откроет стандартное окно с индикатором прогресса и кнопкой отмены, что соответствует стандартам интерфейса 1С.
Разберем типичную ошибку начинающих разработчиков. Метод Состояние() управляет нижней строкой статуса в окне приложения. Когда код уходит на сервер, он выполняется в контексте рабочего процесса (rphost), у которого нет «экрана». Вся информация, которую сервер хочет передать пользователю, должна быть либо возвращена как результат функции, либо записана в доступное обоим контекстам место (база данных, временное хранилище, сообщения пользователю). Помните, что интерфейс — это прерогатива клиента.
Рассмотрим несколько практических советов для эффективной работы индикатора:
Ctrl + Break, что особенно важно при «порционном» методе.Таким образом, выбор метода зависит от архитектуры вашей задачи. Для простых внешних обработок подойдет порционный метод, для серьезных механизмов внутри конфигурации — БСП или самописные фоновые задания через временное хранилище.