При работе с большими объемами данных в 1С:Предприятие программисты часто сталкиваются с проблемой: процесс формирования и записи XML-файла занимает значительное время, в течение которого пользователь видит «песочные часы» и не может взаимодействовать с программой. Рассмотрим подробнее, как перевести этот процесс в асинхронный режим, разберем архитектурные подходы и изучим конкретные примеры реализации.
Когда мы запускаем процедуру формирования XML непосредственно в обработчике нажатия кнопки на форме, выполнение кода происходит в основном потоке клиентского приложения. До тех пор, пока цикл обхода данных не завершится и файл не будет закрыт методом Записать(), интерфейс будет заблокирован. Выясним причину: клиент ждет ответа от сервера или занят локальными вычислениями, не обрабатывая события отрисовки окна.
Для решения этой задачи проанализируем наиболее эффективную схему работы в управляемом приложении:
ФоновыеЗадания позволяет запустить процедуру в отдельном сеансе на сервере.НачатьПолучениеФайлаССервера).Рассмотрим по шагам, как вынести длительную операцию на сервер. Основная логика заключается в том, что клиентская часть лишь инициирует процесс и периодически проверяет его состояние.
Во-первых, создадим экспортную процедуру в общем модуле (например, ОбменДаннымиСервер), которая будет выполнять основную работу. Важно, чтобы модуль имел флаг «Сервер» и «Вызов сервера».
Процедура СформироватьXMLФоновое(АдресХранилища, ПараметрыЗагрузки) Экспорт
ЗаписьXML = Новый ЗаписьXML;
ИмяВременногоФайла = ПолучитьИмяВременногоФайла("xml");
ЗаписьXML.ОткрытьФайл(ИмяВременногоФайла, "UTF-8");
ЗаписьXML.ЗаписатьОбъявлениеXML();
// Эмуляция длительного цикла формирования
ЗаписьXML.ЗаписатьНачалоЭлемента("Root");
Для Счетчик = 1 По ПараметрыЗагрузки.Количество Цикл
// Здесь ваша логика выборки данных
ЗаписьXML.ЗаписатьНачалоЭлемента("Item");
ЗаписьXML.ЗаписатьАтрибут("ID", Строка(Счетчик));
ЗаписьXML.ЗаписатьТекст("Данные элемента");
ЗаписьXML.ЗаписатьКонецЭлемента();
// Опционально: сообщаем о прогрессе
Если Счетчик % 100 = 0 Тогда
Процент = (Счетчик / ПараметрыЗагрузки.Количество) * 100;
СообщитьПрогресс(Процент, "Формирование файла...");
КонецЕсли;
КонецЦикла;
ЗаписьXML.ЗаписатьКонецЭлемента();
ЗаписьXML.Закрыть();
// Помещаем готовый файл во временное хранилище
ДвоичныеДанные = Новый ДвоичныеДанные(ИмяВременногоФайла);
ПоместитьВоВременноеХранилище(ДвоичныеДанные, АдресХранилища);
// Удаляем временный файл с сервера
УдалитьФайлы(ИмяВременногоФайла);
КонецПроцедуры
Во-вторых, на форме обработки нам необходимо запустить это задание. Проанализируем пример запуска с клиента:
&НаКлиенте
Процедура СформироватьXML(Команда)
ПараметрыПроцедуры = Новый Структура;
ПараметрыПроцедуры.Вставить("Количество", 10000);
АдресХранилища = ПоместитьВоВременноеХранилище(Неопределено, УникальныйИдентификатор);
// Запускаем фоновое задание
РезультатЗапуска = ЗапуститьФоновоеЗаданиеНаСервере(АдресХранилища, ПараметрыПроцедуры);
ИдентификаторЗадания = РезультатЗапуска.ИдентификаторЗадания;
// Подключаем обработчик ожидания для проверки статуса
ПодключитьОбработчикОжидания("ПроверитьСтатусЗадания", 2, Ложь);
Состояние("Файл формируется в фоновом режиме...", 0);
КонецПроцедуры
Если ваша конфигурация построена на базе БСП, разберем более современный метод с использованием модуля ДлительныеОперации. Этот подход избавляет от необходимости вручную писать циклы проверки статуса задания.
Посмотрим на пример использования механизма «ДлительныеОперации»:
ДлительныеОперации.ВыполнитьВФоне(), передавая имя процедуры и параметры.Статус и АдресХранилища.ОткрытьФорму("ОбщаяФорма.ДлительнаяОперация").Важный момент: использование БСП позволяет пользователю нажать кнопку «Отмена». В этом случае фоновое задание на сервере будет принудительно завершено, что экономит ресурсы системы.
Проанализируем ситуацию, когда данных настолько много, что даже формирование в памяти может вызвать переполнение. Для этого крайне рекомендуется использовать объект ЗаписьXML.
В отличие от модели DOM (объект ДокументDOM), которая строит все дерево в оперативной памяти, ЗаписьXML работает как последовательный поток. Это позволяет обрабатывать миллионы строк данных с минимальным потреблением RAM. Рассмотрим ключевые преимущества этого объекта:
UTF-8 или Windows-1251.После того как фоновое задание завершилось и данные попали во временное хранилище, нам нужно передать их пользователю. Чтобы и этот процесс не блокировал браузер или тонкий клиент, воспользуемся асинхронными вызовами.
Выясним, как выглядит современный код завершения операции:
&НаКлиенте
Асинх Процедура ЗавершитьФормирование(АдресХранилища)
ПараметрыФайла = Новый ПараметрыПолученияФайла;
ПараметрыФайла.Заголовок = "Выберите путь для сохранения XML";
// Используем асинхронный метод получения файла
Результат = Ждать НачатьПолучениеФайлаССервераАсинх(АдресХранилища, "ExportData.xml", ПараметрыФайла);
Если Результат <> Неопределено Тогда
ПоказатьОповещениеПользователю("Успех", , "Файл успешно сохранен на диск.");
КонецЕсли;
КонецПроцедуры
Использование ключевого слова Асинх и оператора Ждать позволяет писать код в линейном стиле, при этом фактически выполнение будет прерываться на время ожидания действий пользователя (выбора пути в диалоге), не замораживая окно программы.
Часто возникает вопрос: как красиво вывести информацию о ходе выполнения? В старых версиях использовали Состояние(), но в современных интерфейсах лучше применять Оповещения.
Если вам нужно передать информацию о ходе процесса из фонового задания, используйте метод ОбщегоНазначения.СообщитьПрогресс() (если есть БСП) или запись в РегистрСведений, который клиент будет считывать в обработчике ожидания.
Что касается форматирования в строке состояния: помните, что платформа поддерживает только символ переноса строки Символы.ПС. Сложное HTML-форматирование в стандартной панели состояния недоступно. Если требуется наглядный лог, лучше выводить его в текстовое поле на форме после завершения процесса.
Мы выяснили, что для реализации «асинхронной» работы с XML в 1С необходимо комбинировать серверные фоновые задания для расчетов и асинхронные клиентские методы для взаимодействия с файловой системой. Такой подход гарантирует отзывчивость интерфейса даже при выгрузке огромных реестров данных.