Разработчики прикладных решений на платформе 1С часто сталкиваются с необходимостью выполнять ресурсоемкие задачи в фоновом режиме, чтобы интерфейс пользователя оставался отзывчивым. В конфигурациях, построенных на базе Библиотеки стандартных подсистем (БСП), для этого предусмотрены готовые механизмы. Однако самостоятельные попытки реализовать эту логику часто приводят к написанию избыточного кода с ручным опросом временного хранилища. В этой статье мы подробно разберем, как уйти от устаревших методов, перестать вручную настраивать обработчики ожидания и задействовать элегантный типовой интерфейс БСП с автоматическим отображением прогресс-бара.
Проанализируем ситуацию, описанную в теме. Разработчик пытается использовать обработчик ожидания ПодключитьОбработчикОжидания на клиенте и вручную опрашивать сервер, считывая данные о прогрессе из временного хранилища. Дополнительно в коде фигурирует метод ДлительныеОперации.ВыполнитьВФоне.
Выясним причину, почему такой подход считается ошибочным и не рекомендуется к использованию в современных версиях БСП:
ДлительныеОперации.ВыполнитьВФоне признана устаревшей (deprecated). Вместо нее в современных версиях БСП (3.x и выше) используются специализированные методы ДлительныеОперации.ВыполнитьПроцедуру и ДлительныеОперации.ВыполнитьФункцию.Рассмотрим подробнее, как решить эту задачу правильно, используя современные стандарты БСП.
В современных стандартах БСП всю рутинную работу по опросу сервера и визуализации процесса берет на себя клиентский модуль ДлительныеОперацииКлиент. Разработчику требуется лишь правильно настроить параметры ожидания и передавать состояние выполнения из фонового задания с помощью метода ДлительныеОперации.СообщитьПрогресс.
Разберем по шагам, как устроен этот процесс.
Прежде всего, нам нужно подготовить экспортный серверный метод, который будет выполнять ресурсоемкую задачу. Этот метод должен располагаться в модуле, доступном для фонового выполнения (например, в модуле объекта обработки, модуле менеджера или в общем серверном модуле).
Посмотрим на пример реализации такого серверного метода:
Процедура ВыполнитьТяжелыйРасчет(Параметры, АдресРезультата) Экспорт
ПределЦикла = Параметры.ПределЦикла;
// Рассчитываем шаг, чтобы не перегружать систему частыми оповещениями
ШагОповещения = Цел(ПределЦикла / 50);
Если ШагОповещения = 0 Тогда
ШагОповещения = 1;
КонецЕсли;
Для Счетчик = 1 По ПределЦикла Цикл
// Здесь выполняется полезная работа (например, обработка данных)
// ...
// Оповещаем клиентское приложение о текущем прогрессе
Если Счетчик % ШагОповещения = 0 Тогда
Процент = Окр(Счетчик * 100 / ПределЦикла);
ТекстПояснения = СтрШаблон("Обработано объектов: %1 из %2", Счетчик, ПределЦикла);
// Специализированный метод БСП автоматически доставит данные на клиент
ДлительныеОперации.СообщитьПрогресс(Процент, ТекстПояснения);
КонецЕсли;
КонецЦикла;
// Помещаем финальный результат во временное хранилище
СтруктураРезультата = Новый Структура("Статус", "Успешно");
ПоместитьВоВременноеХранилище(СтруктураРезультата, АдресРезультата);
КонецПроцедуры
В данном коде ключевым является использование метода ДлительныеОперации.СообщитьПрогресс. Он избавляет нас от необходимости вручную управлять адресом временного хранилища для передачи статуса выполнения.
Теперь перейдем к модулю формы нашей обработки. Нам нужно инициировать запуск фонового задания на сервере, настроить параметры отображения прогресс-бара и передать управление интерактивному окну БСП.
Посмотрим, как выглядит программный код запуска:
&НаКлиенте
Процедура ЗапуститьОбработку(Команда)
// 1. Инициируем запуск длительной операции на сервере
СтруктураОперации = НачатьДлительнуюОперациюНаСервере();
Если СтруктураОперации.Статус = "Выполняется" Тогда
// 2. Настраиваем параметры отображения окна ожидания
ПараметрыОжидания = ДлительныеОперацииКлиент.ПараметрыОжидания(ЭтотОбъект);
ПараметрыОжидания.ВыводитьПрогрессВыполнения = Истина; // Включаем показ прогресс-бара!
ПараметрыОжидания.ВыводитьСообщения = Истина;
ПараметрыОжидания.Интервал = 2; // Частота опроса сервера в секундах
ПараметрыОжидания.ТекстОжидания = "Выполняется обработка данных...";
// 3. Задаем процедуру обратного вызова при завершении
ОповещениеОЗавершении = Новый ОписаниеОповещения("ПослеЗавершенияОперации", ЭтотОбъект);
// 4. Передаем управление подсистеме БСП
ДлительныеОперацииКлиент.ОжидатьЗавершение(СтруктураОперации, ОповещениеОЗавершении, ПараметрыОжидания);
ИначеЕсли СтруктураОперации.Статус = "Выполнено" Тогда
// Если операция завершилась мгновенно на сервере
ПослеЗавершенияОперации(СтруктураОперации, Неопределено);
КонецЕсли;
КонецПроцедуры
&НаСервере
Функция НачатьДлительнуюОперациюНаСервере()
// Задаем параметры запуска фонового процесса
ПараметрыВыполнения = ДлительныеОперации.ПараметрыВыполненияПроцедуры(УникальныйИдентификатор);
ПараметрыВыполнения.НаименованиеФоновогоЗадания = "Пример выполнения фонового расчета БСП";
// Подготавливаем параметры для нашей экспортной процедуры
ПараметрыМетода = Новый Структура;
ПараметрыМетода.Вставить("ПределЦикла", 10000);
// Запускаем процедуру в фоновом задании
ИмяМетода = "Обработка.МояОбработка.МодульОбъекта.ВыполнитьТяжелыйРасчет";
Возврат ДлительныеОперации.ВыполнитьПроцедуру(
УникальныйИдентификатор,
ИмяМетода,
ПараметрыМетода,
ПараметрыВыполнения
);
КонецФункции
Обратите внимание на свойство ПараметрыОжидания.ВыводитьПрогрессВыполнения. Установка его в значение Истина является ключевым действием, которое заставляет БСП показывать окно с динамически обновляемым индикатором выполнения.
Когда фоновое задание полностью завершает свою работу, типовое окно ожидания БСП автоматически закрывается, и управление передается в указанную нами процедуру оповещения.
Проанализируем структуру процедуры обратного вызова на клиенте:
&НаКлиенте
Процедура ПослеЗавершенияОперации(РезультатОперации, ДополнительныеПараметры) Экспорт
Если РезультатОперации = Неопределено Тогда
// Сюда мы попадаем, если пользователь закрыл окно ожидания вручную (отменил операцию)
Возврат;
КонецЕсли;
Если РезультатОперации.Статус = "Выполнено" Тогда
// Получаем результат работы из временного хранилища
СтруктураРезультата = ПолучитьРезультатИзХранилища(РезультатОперации.АдресРезультата);
ПоказатьОповещениеПользователя("Успешно!", , "Обработка данных завершена.");
ИначеЕсли РезультатОперации.Статус = "Ошибка" Тогда
// Обрабатываем возникшую в фоновом задании ошибку
ВызватьИсключение РезультатОперации.ПодробноеПредставлениеОшибки;
КонецЕсли;
КонецПроцедуры
&НаСервереБезКонтекста
Функция ПолучитьРезультатИзХранилища(АдресРезультата)
Возврат ПолучитьИзВременногоХранилища(АдресРезультата);
EndФункции
При использовании стандартного механизма прогресс-бара БСП важно помнить о ряде ограничений платформы 1С:
ДлительныеОперации.СообщитьПрогресс не более 100 раз за весь период работы фонового задания. Слишком частая отправка прогресса (например, на каждой итерации быстрого цикла) приводит к сильной перегрузке сетевого трафика между клиентом и сервером приложений, а также к неоправданному потреблению оперативной памяти. Обязательно рассчитывайте шаг оповещения, как было показано в Шаге 1.СообщитьПрогресс абсолютно не будут работать, если ваш основной цикл выполнения задачи обернут в общую транзакцию базы данных (между операторами НачатьТранзакцию() и ЗафиксироватьТранзакцию()). Платформа физически не сможет передать промежуточные пакеты данных на клиентскую сторону до тех пор, пока транзакция не зафиксируется на сервере.ДлительныеОперации.СообщитьПрогресс(Процент, Текст, ДополнительныеПараметры) позволяет передавать на клиент структурированные вспомогательные данные. Они должны быть простыми и сериализуемыми (числа, строки, булево, простые структуры).ВыполнитьПроцедуру. В БСП для этого существует специализированный метод ДлительныеОперации.ВыполнитьПроцедуруМодуляОбъектаОбработки, который берет на себя безопасное выполнение кода внешнего файла в фоне.Используя рассмотренную нами схему, мы получаем надежный, отказоустойчивый и полностью соответствующий стандартам разработки 1С код, который гармонично вписывается в интерфейс любой современной типовой конфигурации.