Как передать несколько табличных документов через временное хранилище на клиент?

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

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

Анализируем причину: время жизни данных во временном хранилище

Посмотрим на синтаксис метода платформы: ПоместитьВоВременноеХранилище(<Данные>, <Адрес>). Второй параметр является необязательным, и именно в нем кроется причина проблемы.

Выясним причину такого поведения платформы:

  1. Вызов без передачи адреса: если второй параметр не передан, платформа создает новый уникальный адрес, но время жизни таких данных ограничено одним последующим серверным вызовом из модуля формы или общего модуля.
  2. Срабатывание очистки: когда клиент получает первый адрес, он делает серверный вызов (контекстный или неконтекстный), чтобы прочитать данные или продолжить обработку. В момент этого обращения сервер 1С автоматически очищает все временные данные, у которых не был привязан владелец. В результате все остальные адреса, сформированные в цикле, уничтожаются.
  3. Перезапись переменной: типичная ошибка в цикле — сохранение результата метода в одну и ту же строковую переменную вида Адрес = ПоместитьВоВременноеХранилище(...) без сохранения ссылок в массив.

Решение 1. Привязка адреса к идентификатору формы

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

Рассмотрим пример формирования документов на сервере с сохранением ссылок в массив:


&НаСервере
Функция СформироватьТабличныеДокументыНаСервере()
    МассивАдресов = Новый Массив;
    
    Для Счетчик = 1 По 5 Цикл
        ТабДок = Новый ТабличныйДокумент;
        // Заполняем документ данными
        
        // Передаем УникальныйИдентификатор текущей формы вторым параметром
        АдресФайла = ПоместитьВоВременноеХранилище(ТабДок, ЭтаФорма.УникальныйИдентификатор);
        МассивАдресов.Добавить(АдресФайла);
    КонецЦикла;
    
    Возврат МассивАдресов;
КонецФункции

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

Решение 2. Упаковка документов в единую коллекцию

Вместо многократного помещения отдельных объектов во временное хранилище гораздо эффективнее собрать все сформированные документы в единый контейнер — Массив или Структура — и поместить во временное хранилище только один объект.

Посмотрим на пример реализации:


&НаСервере
Функция ПоместитьВсеДокументыВХранилище()
    СписокДокументов = Новый Массив;
    
    Для Индекс = 1 По 3 Цикл
        ТабДок = Новый ТабличныйДокумент;
        // Формирование содержимого
        СписокДокументов.Добавить(ТабДок);
    КонецЦикла;
    
    // Помещаем весь массив за один вызов
    Возврат ПоместитьВоВременноеХранилище(СписокДокументов, ЭтаФорма.УникальныйИдентификатор);
КонецФункции

&НаКлиенте
Процедура ПолучитьДокументы()
    АдресХранилища = ПоместитьВсеДокументыВХранилище();
    
    // Извлекаем массив со всеми табличными документами
    МассивДокументов = ПолучитьИзВременногоХранилища(АдресХранилища);
    
    Для Каждого ТекТабДок Из МассивДокументов Цикл
        // Работаем с каждым табличным документом на клиенте
        ТекТабДок.Показать();
    КонецЦикла;
КонецПроцедуры

Такой подход избавляет от необходимости генерировать множество адресов и уменьшает накладные расходы на обращение к временному хранилищу.

Решение 3. Передача массива табличных документов напрямую

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

Разберем компактный вариант передачи без промежуточных адресов:


&НаСервереБезКонтекста
Функция ПолучитьМассивПечатныхФорм()
    Результат = Новый Массив;
    
    Для Каждого Элемент Из СписокОбъектов Цикл
        ТабДок = Новый ТабличныйДокумент;
        // Заполнение макета
        Результат.Добавить(ТабДок);
    КонецЦикла;
    
    Возврат Результат;
КонецФункции

Решение 4. Выгрузка файлов на диск через НачатьПолучениеФайлов

Если конечной целью является сохранение документов на диск клиента (например, в форматах PDF или Excel), наиболее производительным решением будет пакетная передача двоичных данных.

Разберем по шагам алгоритм пакетного сохранения:

  1. На сервере сохраняем каждый ТабличныйДокумент во временный файл нужного формата.
  2. Считываем файл в объект ДвоичныеДанные.
  3. Помещаем двоичные данные во временное хранилище и сохраняем сформированный адрес.
  4. На клиенте формируем массив объектов ОписаниеПередаваемогоФайла и вызываем асинхронную процедуру НачатьПолучениеФайлов. Это позволяет сохранить все файлы на диск за одну операцию без вывода множества диалоговых окон пользователю.

Контроль памяти и фоновые задания

Обратим внимание на управление ресурсами сервера при работе с временным хранилищем:

  1. Использование произвольного идентификатора: если передать Новый УникальныйИдентификатор вместо идентификатора формы, данные останутся в памяти рабочего процесса rphost до завершения сеанса пользователя. Чтобы не перегружать оперативную память сервера большими табличными документами, вызывайте УдалитьИзВременногоХранилища(Адрес) сразу после того, как данные прочитаны на клиенте.
  2. Фоновые задания: при длительных операциях фоновый поток не имеет доступа к форме. В этом случае адрес хранилища создается в основном потоке клиента/сервера с сеансовым идентификатором, передается в фоновое задание в качестве параметра, заполняется там, а после считывания клиентом удаляется вручную.
← На главную