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