Как реализовать асинхронную запись в XML-файл в 1С, чтобы не зависал интерфейс?

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

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

Проблема синхронного выполнения и выбор стратегии

Когда мы запускаем процедуру формирования XML непосредственно в обработчике нажатия кнопки на форме, выполнение кода происходит в основном потоке клиентского приложения. До тех пор, пока цикл обхода данных не завершится и файл не будет закрыт методом Записать(), интерфейс будет заблокирован. Выясним причину: клиент ждет ответа от сервера или занят локальными вычислениями, не обрабатывая события отрисовки окна.

Для решения этой задачи проанализируем наиболее эффективную схему работы в управляемом приложении:

  1. Разделение формирования и сохранения: Непосредственное формирование данных должно происходить на сервере в фоновом режиме.
  2. Использование фоновых заданий: Механизм ФоновыеЗадания позволяет запустить процедуру в отдельном сеансе на сервере.
  3. Передача результата: После завершения формирования файл передается на клиент через временное хранилище.
  4. Асинхронные методы платформы: Для финального сохранения файла на диск используются немодальные методы (НачатьПолучениеФайлаССервера).

Реализация формирования 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);
    
КонецПроцедуры

Использование Библиотеки стандартных подсистем (БСП)

Если ваша конфигурация построена на базе БСП, разберем более современный метод с использованием модуля ДлительныеОперации. Этот подход избавляет от необходимости вручную писать циклы проверки статуса задания.

Посмотрим на пример использования механизма «ДлительныеОперации»:

  1. Вызываем ДлительныеОперации.ВыполнитьВФоне(), передавая имя процедуры и параметры.
  2. Метод возвращает структуру, содержащую Статус и АдресХранилища.
  3. Если процесс длительный, БСП сама откроет окно ожидания с индикатором, если вы используете стандартный метод ОткрытьФорму("ОбщаяФорма.ДлительнаяОперация").

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

Оптимизация записи больших XML-документов

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

В отличие от модели DOM (объект ДокументDOM), которая строит все дерево в оперативной памяти, ЗаписьXML работает как последовательный поток. Это позволяет обрабатывать миллионы строк данных с минимальным потреблением RAM. Рассмотрим ключевые преимущества этого объекта:

Асинхронное получение файла на клиенте (Платформа 8.3.18+)

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

Выясним, как выглядит современный код завершения операции:


&НаКлиенте
Асинх Процедура ЗавершитьФормирование(АдресХранилища)
    
    ПараметрыФайла = Новый ПараметрыПолученияФайла;
    ПараметрыФайла.Заголовок = "Выберите путь для сохранения XML";
    
    // Используем асинхронный метод получения файла
    Результат = Ждать НачатьПолучениеФайлаССервераАсинх(АдресХранилища, "ExportData.xml", ПараметрыФайла);
    
    Если Результат <> Неопределено Тогда
        ПоказатьОповещениеПользователю("Успех", , "Файл успешно сохранен на диск.");
    КонецЕсли;
    
КонецПроцедуры

Использование ключевого слова Асинх и оператора Ждать позволяет писать код в линейном стиле, при этом фактически выполнение будет прерываться на время ожидания действий пользователя (выбора пути в диалоге), не замораживая окно программы.

Отображение прогресса и форматирование строк

Часто возникает вопрос: как красиво вывести информацию о ходе выполнения? В старых версиях использовали Состояние(), но в современных интерфейсах лучше применять Оповещения.

Если вам нужно передать информацию о ходе процесса из фонового задания, используйте метод ОбщегоНазначения.СообщитьПрогресс() (если есть БСП) или запись в РегистрСведений, который клиент будет считывать в обработчике ожидания.

Что касается форматирования в строке состояния: помните, что платформа поддерживает только символ переноса строки Символы.ПС. Сложное HTML-форматирование в стандартной панели состояния недоступно. Если требуется наглядный лог, лучше выводить его в текстовое поле на форме после завершения процесса.

Резюме

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

← На главную