Как заполнить табличную часть внешней обработки из фонового задания в 1С 8.3?

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

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

Почему нельзя просто передать форму в фоновое задание?

Прежде всего, проанализируем технические ограничения платформы 1С:Предприятие 8.3. Фоновое задание запускается в отдельном сеансе на стороне сервера. У этого сеанса нет доступа к оперативной памяти клиентского приложения, где «живет» форма. Платформа использует механизм сериализации (преобразования объекта в поток данных) для передачи параметров между клиентом и сервером, но такие объекты, как УправляемаяФорма или ДанныеФормыСтруктура, не могут быть сериализованы. Наша задача — разделить логику на подготовку данных и их отображение.

Алгоритм решения через Временное хранилище

Рассмотрим классический подход, который будет работать в любой конфигурации. Суть метода заключается в том, что фоновое задание формирует «безликую» ТаблицаЗначений, сохраняет ее в специальное хранилище на сервере, а форма по завершении задания забирает эти данные и заполняет свою табличную часть.

Разберем процесс по шагам:

Шаг 1. Подготовка процедуры запуска на сервере

Нам необходимо создать процедуру в модуле объекта обработки (или в общем модуле), которая будет выполнять расчеты. Важно помнить, что если обработка внешняя, фоновое задание должно иметь доступ к её коду. Рассмотрим пример запуска фонового задания из модуля формы:


&НаСервере
Функция ЗапуститьЗаполнениеНаСервере()
    
    // Создаем уникальный адрес во временном хранилище для получения результата
    АдресРезультата = ПоместитьВоВременноеХранилище(Неопределено, ЭтаФорма.УникальныйИдентификатор);
    
    // Подготавливаем параметры для фонового задания
    ПараметрыЗадания = Новый Структура;
    ПараметрыЗадания.Вставить("ДатаНачала", Объект.ПериодНачала);
    ПараметрыЗадания.Вставить("ДатаОкончания", Объект.ПериодОкончания);
    ПараметрыЗадания.Вставить("АдресРезультата", АдресРезультата);
    
    // Если обработка внешняя, нужно передать её двоичные данные или путь
    НаименованиеЗадания = "Заполнение заказов в фоне";
    
    // Запускаем задание. В данном примере вызывается экспортная процедура из общего модуля
    Задание = ФоновыеЗадания.Выполнить("МойОбщийМодульСервер.СформироватьСписокЗаказов", ПараметрыЗадания, , НаименованиеЗадания);
    
    Возврат Новый Структура("ИдентификаторЗадания, АдресРезультата", Задание.УникальныйИдентификатор, АдресРезультата);

КонецФункции

Шаг 2. Код фонового задания (Сервер)

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


Процедура СформироватьСписокЗаказов(Параметры, АдресРезультата) Экспорт
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   ЗаказПокупателя.Ссылка КАК Заказ
        |ИЗ
        |   Документ.ЗаказПокупателя КАК ЗаказПокупателя
        |       ЛЕВОЕ СОЕДИНЕНИЕ Документ.РеализацияТоваровУслуг КАК Реализация
        |       ПО Реализация.ДокументОснование = ЗаказПокупателя.Ссылка
        |ГДЕ
        |   ЗаказПокупателя.Дата МЕЖДУ &ДатаНачала И &ДатаОкончания
        |   И Реализация.Ссылка ЕСТЬ NULL";
    
    Запрос.УстановитьПараметр("ДатаНачала", Параметры.ДатаНачала);
    Запрос.УстановитьПараметр("ДатаОкончания", Параметры.ДатаОкончания);
    
    РезультатТЗ = Запрос.Выполнить().Выгрузить();
    
    // Помещаем результат в хранилище, чтобы клиент мог его забрать
    ПоместитьВоВременноеХранилище(РезультатТЗ, Параметры.АдресРезультата);
    
КонецПроцедуры

Организация ожидания на клиенте

Чтобы форма «узнала» о завершении задания, не блокируя пользователя, используем ПодключитьОбработчикОжидания. Проанализируем состояние задания через определенные интервалы времени.


&НаКлиенте
Переменная ИдентификаторФоновогоЗадания;
Переменная АдресХранилищаРезультата;

&НаКлиенте
Процедура КомандаЗаполнить(Команда)
    
    РезультатЗапуска = ЗапуститьЗаполнениеНаСервере();
    ИдентификаторФоновогоЗадания = РезультатЗапуска.ИдентификаторЗадания;
    АдресХранилищаРезультата = РезультатЗапуска.АдресРезультата;
    
    // Блокируем только нужные элементы, а не всю форму
    Элементы.ГруппаПараметры.Доступность = Ложь;
    
    // Запускаем проверку каждые 2 секунды
    ПодключитьОбработчикОжидания("ПроверитьЗавершениеЗадания", 2);
    
КонецПроцедуры

&НаКлиенте
Процедура ПроверитьЗавершениеЗадания()
    
    Если ЗаданиеЗавершено(ИдентификаторФоновогоЗадания) Тогда
        ОтключитьОбработчикОжидания("ПроверитьЗавершениеЗадания");
        ЗагрузитьРезультатИзХранилища();
        Элементы.ГруппаПараметры.Доступность = Истина;
    КонецЕсли;
    
КонецПроцедуры

Использование механизмов БСП для длительных операций

Если вы работаете в современной конфигурации (например, БП 3.0, ERP, УТ 11), настоятельно рекомендуем использовать стандартную подсистему «Длительные операции». Это позволит избежать написания «велосипедов» и обеспечит штатное отображение прогресс-бара.

Рассмотрим, как это упрощает код:

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

Пример получения данных через БСП:


&НаСервере
Процедура ЗавершениеФоновогоЗаданияНаСервере()
    
    // Получаем данные из временного хранилища БСП
    РезультатЗадания = ПолучитьИзВременногоХранилища(АдресХранилищаРезультата);
    
    Если ТипЗнч(РезультатЗадания) = Тип("ТаблицаЗначений") Тогда
        Объект.ТЧ_Заказы.Загрузить(РезультатЗадания);
    КонецЕсли;
    
КонецПроцедуры

Оптимизация при очень больших объемах

Выясним еще один важный момент: если в таблице значений после фонового задания оказывается 50 000 строк, прямая загрузка в ДанныеФормыКоллекция (ТЧ формы) на сервере может быть медленной. В этом случае проанализируем ситуацию и предложим альтернативу:

Подведем итоги

Заполнение табличной части из фонового задания — это не только перенос кода с клиента на сервер, но и правильная организация обмена данными. Мы рассмотрели метод с использованием ВременногоХранилища, который является наиболее гибким. Помните, что во время работы фонового задания пользователь может закрыть форму. Поэтому всегда указывайте УникальныйИдентификатор формы при помещении данных в хранилище, чтобы система автоматически очистила память после закрытия окна.

← На главную