Как правильно передавать и выводить большие объемы данных из фонового задания в 1С?

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

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

Выясним причину зависания интерфейса при передаче таблицы значений

Рассмотрим типичную схему работы: фоновое задание формирует объект типа ТаблицаЗначений, помещает его во временное хранилище, после чего клиентский сеанс забирает адрес хранилища и загружает данные в элемент формы.

Посмотрим на пример кода серверной процедуры, которая обычно вызывает задержку:


&НаСервере
Процедура ПолучитьТаблицуПоРезультатамФоновогоЗадания(АдресТаблицы)
    
    // Получение ТЗ из хранилища и загрузка в коллекцию формы
    ТаблицаНаФорме.Загрузить(ПолучитьИзВременногоХранилища(АдресТаблицы));
    
КонецПроцедуры

Хотя сам код выглядит минималистично, на практике выполнение процедуры для десятков и сотен тысяч строк занимает десятки секунд. Разберем, почему это происходит:

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

Важно понимать ключевое ограничение платформы: **напрямую передать элементы формы или реквизит контекста формы в фоновое задание невозможно**, так как фоновое задание не имеет клиентского контекста и пользовательского интерфейса.

Решение 1. Переход на Табличный документ и стандартную подсистему БСП

Наиболее эффективным решением при работе с отчетами является отказ от использования табличной части или таблицы значений на форме в пользу объекта ТабличныйДокумент.

Рассмотрим преимущества вывода данных в ТабличныйДокумент:

  1. Объект ТабличныйДокумент значительно «легче» для контекста тонкого клиента, так как не создает сложную структуру объектов ДанныеФормыЭлементКоллекции для каждой строки.
  2. Стандартные механизмы библиотеки стандартных подсистем (БСП) и СКД имеют встроенную оптимизированную систему фонового формирования. При формировании отчета через подсистему «Варианты отчетов» передача готового табличного документа на клиент происходит без задержек и заморозки интерфейса.

Если специфика задачи позволяет отображать результат в виде печатной формы или отчета, следует формировать ТабличныйДокумент непосредственно в фоновом задании, помещать его в хранилище и выводить на форме в элемент поля табличного документа.

Решение 2. Использование Динамического списка через служебный регистр

Если пользователю необходима именно интерактивная таблица с возможностью отбора, сортировки и перехода к объектам, вместо таблицы значений рекомендуем использовать объект ДинамическийСписок.

Проанализируем алгоритм реализации данного подхода:

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

Главный плюс этого способа — **виртуализация данных**. ДинамическийСписок считывает и передает на тонкий клиент только те строки, которые в данный момент видны на экране пользователя, благодаря чему интерфейс открывается мгновенно при любом объеме строк.

Решение 3. Постраничный (порционный) вывод

Если данные необходимо обрабатывать в таблице значений, но их объем слишком велик, разберем способ постраничной подгрузки.

Суть метода заключается в том, что фоновое задание сохраняет полную ТаблицуЗначений во временном хранилище (или файле на сервере), а процедура формы запрашивает и загружает данные небольшими порциями (например, по 100–200 строк).

Посмотрим на пример функции выбора порции данных на сервере:


&НаСервере
Процедура ЗагрузитьСтраницуДанных(АдресХранилища, НомерСтраницы, РазмерСтраницы)
    
    ТЗПолная = ПолучитьИзВременногоХранилища(АдресХранилища);
    Если ТЗПолная = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    // Очищаем текущие данные на форме
    ТаблицаНаФорме.Очистить();
    
    НачальныйИндекс = (НомерСтраницы - 1) * РазмерСтраницы;
    КонечныйИндекс = Мин(НачальныйИндекс + РазмерСтраницы - 1, ТЗПолная.Количество() - 1);
    
    Для Индекс = НачальныйИндекс По КонечныйИндекс Доклопать
        ЗаполнитьЗначенияСвойств(ТаблицаНаФорме.Добавить(), ТЗПолная[Индекс]);
    КонецЦикла;
    
КонецПроцедуры

Пользователю предоставляются кнопки навигации («Вперед», «Назад») или подгрузка данных реализуется при прокрутке, что исключает передачи огромных массивов контекста за один вызов.

Решение 4. Отключение видимости элемента формы на время загрузки

В случаях, когда отказаться от загрузки большого массива строк в ДанныеФормыКоллекция невозможно, уменьшить задержку вызова поможет временное отключение отображения элемента формы.

Рассмотрим порядок действий:


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

Скрытие элемента управления Элементы.ТаблицаНаФорме.Видимость = Ложь перед вызовом ЗначениеВРеквизитФормы() или Загрузить() позволяет платформе не тратить ресурсы на перерисовывание интерфейса для каждой вставляемой строки во время выполнения серверного вызова.

← На главную