Как дождаться завершения загрузки файлов на сервер перед закрытием формы в 1С

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

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

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

Метод 1: Использование управляющего флага в обработчике ПередЗаписью

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

Рассмотрим по шагам, как это реализовать:

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

Проанализируем пример кода для реализации этой логики:


&НаКлиенте
Перем ВыполняетсяЗагрузка; // Локальная переменная для блокировки повторных нажатий

&НаКлиенте
Процедура ПередЗаписью(Отказ, ПараметрыЗаписи)
	
	Если ФайлыЗагружены Тогда 
		// Если файлы уже на сервере, разрешаем штатную запись
		Возврат;
	КонецЕсли;
	
	// Если файлы еще не загружены, отменяем текущую запись
	Отказ = Истина;
	
	// Запускаем асинхронный процесс помещения файлов
	ВыполнитьЗагрузкуФайловНаСервер(ПараметрыЗаписи);
	
КонецПроцедуры

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

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

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

Метод 2: Замена стандартной команды на пользовательскую

Иногда проще полностью контролировать поведение интерфейса, заменив стандартную кнопку «Провести и закрыть» на собственную. Это позволяет избежать сложных манипуляций в ПередЗаписью и сделать логику более линейной для понимания.

Разберем алгоритм работы такой кнопки:

  1. Пользователь нажимает «Загрузить и сохранить».
  2. Программа проверяет наличие выбранных файлов на клиенте.
  3. Запускается асинхронная загрузка.
  4. В обработчике завершения загрузки вызывается серверный метод для сохранения ссылок на файлы в базе данных и выполняется программное закрытие формы через ЭтаФорма.Закрыть().

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

Метод 3: Организация очереди загрузки через промежуточный регистр

Рассмотрим ситуацию, когда файлов много (например, 10-15 фотографий высокого разрешения) и ожидание их загрузки раздражает пользователя. В этом случае мы можем применить стратегию «отложенной обработки».

Для этого выполним следующие действия:

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

Важный нюанс: данный метод требует, чтобы сервер 1С имел прямой доступ к файловой системе клиента (что редкость в веб-клиенте) или чтобы файлы были предварительно помещены в общую сетевую папку (шару). Если работа идет через интернет, этот способ потребует использования внешней компоненты для фоновой передачи данных по протоколу HTTP или FTP.

Метод 4: Оптимизация через пакетную передачу (НачатьПомещениеФайлов)

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

Проанализируем пример правильного формирования массива для пакетной загрузки:


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

Использование метода НачатьПомещениеФайлов (во множественном числе) позволяет платформе оптимизировать трафик и передать все данные максимально быстро, используя один поток передачи.

Важные замечания по безопасности и стабильности

При реализации любого из перечисленных методов, следует помнить о следующих моментах:

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

← На главную