При разработке сложных систем на платформе 1С:Предприятие часто возникает ситуация, когда тяжелый программный код выполняется на сервере в течение длительного времени (от нескольких минут до нескольких часов). Если запустить такой код напрямую, клиентское приложение «зависает», а пользователь не понимает, на каком этапе находится процесс и сколько времени осталось до завершения. Рассмотрим, как сделать интерфейс отзывчивым и реализовать корректное отображение прогресса выполнения серверных задач.
Главная сложность заключается в том, что серверный контекст изолирован от клиентского. Код, исполняемый на сервере, не может напрямую «достучаться» до элементов формы на клиенте, чтобы обновить значение индикатора. Проанализируем основной алгоритм решения этой задачи:
Если ваша конфигурация построена на базе БСП, разберем наиболее правильный и современный способ реализации через программный интерфейс модуля ДлительныеОперации. Это избавляет разработчика от необходимости вручную прописывать логику опроса и создания фоновых заданий.
На стороне сервера внутри процедуры, выполняющей расчет, необходимо использовать метод СообщитьПрогресс. Рассмотрим пример кода:
Процедура ВыполнитьДлительнуюОперацию(Параметры, АдресРезультата) Экспорт
ВсегоИтераций = Параметры.Количество();
Для Итерация = 1 По ВсегоИтераций Цикл
// Основная логика обработки данных
ОбработатьОбъект(Параметры[Итерация - 1]);
// Расчет процента и информирование системы
Процент = (Итерация / ВсегоИтераций) * 100;
ТекстСообщения = "Обработка объектов: " + Итерация + " из " + ВсегоИтераций;
ДлительныеОперации.СообщитьПрогресс(ЦелоЧисло(Процент), ТекстСообщения);
КонецЦикла;
КонецПроцедуры
На стороне клиента мы используем стандартное окно ожидания. Метод ДлительныеОперацииКлиент.ОжидатьЗавершения берет на себя всю работу по визуализации прогресс-бара и обработке завершения задания. Это выглядит эстетично и соответствует стандартам разработки 1С (подробнее можно посмотреть в справочнике по методам БСП).
Если использование БСП по каким-то причинам невозможно, проанализируем ситуацию реализации «с нуля». В этом случае мы будем использовать ВременноеХранилище для обмена данными между фоновым заданием и основной формой или использовать готовую библиотеку для создания конвейеров фоновых задач.
Шаг 1. Запуск задания. При нажатии на кнопку в форме мы создаем уникальный идентификатор (УИД) и запускаем фоновое задание, передавая ему адрес во временном хранилище.
&НаКлиенте
Процедура ЗапуститьОбработку(Команда)
АдресХранилища = ПоместитьВоВременноеХранилище(Неопределено, ЭтаФорма.УникальныйИдентификатор);
ПараметрыФЗ = Новый Структура("Адрес", АдресХранилища);
// Запускаем серверный метод в фоне
Задание = ЗапуститьФоновоеЗаданиеНаСервере(ПараметрыФЗ);
// Подключаем обработчик ожидания для обновления индикатора
ПодключитьОбработчикОжидания("ОбновитьПрогрессНаФорме", 2, Ложь);
КонецПроцедуры
Шаг 2. Запись прогресса на сервере. Внутри фонового задания мы будем обновлять структуру во временном хранилище (это актуально и при реализации выполнения произвольного кода под WEB-клиентом). Посмотрим на пример кода:
Процедура ФоноваяПроцедура(Параметры) Экспорт
Для Счетчик = 1 По 100 Цикл
// Имитация работы
ТаймАут(1);
ДанныеПрогресса = Новый Структура;
ДанныеПрогресса.Вставить("Процент", Счетчик);
ДанныеПрогресса.Вставить("Текст", "Выполнено: " + Счетчик + "%");
ПоместитьВоВременноеХранилище(ДанныеПрогресса, Параметры.Адрес);
КонецЦикла;
КонецПроцедуры
Шаг 3. Чтение на клиенте. В обработчике ожидания мы считываем данные. Важно помнить, что чтение из хранилища по адресу выполняется очень быстро и не создает нагрузки на базу данных, в отличие от использования регистров сведений или констант.
Выясним причину, по которой этот метод считается наиболее современным. Традиционный опрос сервера (polling) заставляет клиент каждые несколько секунд делать лишние запросы. Система взаимодействия позволяет серверу самому «толкнуть» данные клиенту.
Разберем алгоритм:
СистемаВзаимодействия.СоздатьСообщение().Элементы.ИндикаторПрогресса.Значение обновляется мгновенно.Важный нюанс: Этот способ требует настроенного сервера системы взаимодействия, но он обеспечивает минимальную задержку и отсутствие лишнего трафика.
Чтобы прогресс-бар был по-настоящему информативным, недостаточно просто показывать проценты. Рассмотрим, как рассчитать примерное время до окончания операции. Выясним формулу, которую стоит внедрить в серверный код:
ОставшеесяВремя = (ПрошедшееВремя / ТекущийПроцент) * (100 - ТекущийПроцент)
Проанализируем ситуацию: если за 10 минут выполнилось 20%, то общий объем работ займет 50 минут, а осталось — 40 минут. Передавая это значение в структуру прогресса, мы можем вывести пользователю текст: «Осталось примерно 15 минут».
При реализации индикации важно не допустить деградации производительности самого алгоритма. Разберем основные правила:
СообщитьПрогресс не чаще одного раза в 0.5–1 секунду.Если ТекущаяДата() - ДатаПоследнегоОбновления > 1 Тогда....ПолучитьСообщенияПользователю() для объекта фонового задания также позволяет извлекать текстовую информацию о ходе процесса без использования временного хранилища.Таким образом, выбор метода зависит от архитектуры вашей базы. Для типовых решений на БСП — это однозначно встроенные ДлительныеОперации. Для самописных систем — комбинация фонового задания и временного хранилища либо современная Система взаимодействия.