При разработке обработок загрузки больших массивов данных (например, объемных прайс-листов из Excel) часто возникает необходимость дать пользователю возможность прервать процесс. В старых версиях платформы 1С на обычных формах это решалось простым модальным вызовом Вопрос() прямо внутри цикла загрузки. Однако в парадигме управляемых форм (УФ) и интерфейса "Такси" использование модальных окон запрещено или настоятельно не рекомендуется.
Если мы попытаемся использовать немодальный метод ПоказатьВопрос() с обработкой оповещения, мы столкнемся с так называемой проблемой асинхронности: код пойдет выполняться дальше, цикл не прервется и не будет дожидаться ответа пользователя. Разберем подробно, как правильно решить эту задачу, сохраняя отзывчивость интерфейса и корректную архитектуру клиент-серверного взаимодействия.
Если конфигурация работает на платформе 1С:Предприятие 8.3.18 и выше, мы можем использовать современные механизмы асинхронного программирования. Посмотрим на новые модификаторы Асинх и оператор Ждать, которые позволяют приостановить выполнение процедуры (не вешая интерфейс) до получения ответа от пользователя.
Рассмотрим пример реализации такого цикла загрузки:
&НаКлиенте
Асинх Процедура ЗагрузитьПрайсАсинхронно()
СчетчикСтрок = 0;
Для Каждого СтрокаПрайса Из ДанныеЭксель Цикл
// Здесь происходит чтение или передача данных строки
СчетчикСтрок = СчетчикСтрок + 1;
// Каждые 100 строк спрашиваем пользователя
Если (СчетчикСтрок % 100) = 0 Тогда
// Выполнение остановится здесь и будет ждать ответа, интерфейс не зависнет!
Ответ = Ждать ВопросАсинх("Загружено " + СчетчикСтрок + " строк. Продолжить загрузку?", РежимДиалогаВопрос.ДаНет);
Если Ответ = КодВозвратаДиалога.Нет Тогда
Сообщить("Загрузка прервана пользователем.");
Прервать; // Стандартный выход из цикла
КонецЕсли;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
В этом подходе нам не нужно разрывать цикл или писать сложные обработчики оповещений с передачей контекста. Метод ВопросАсинх() вместе с Ждать элегантно решает проблему.
Проанализируем ситуацию с точки зрения производительности. Перебирать огромный Excel-файл на клиенте и построчно дергать сервер для записи данных — это крайне неэффективно. Правильная логика приложения (особенно в тонком и веб-клиенте) задумывается иначе.
Вместо того чтобы задавать вопросы в цикле, перенесем выполнение задачи на сервер в фоновое задание и дадим пользователю кнопку "Отмена". Разберем по шагам этот алгоритм:
ТабличныйДокумент.Прочитать() уже на сервере.ДлительныеОперации.ВыполнитьВФоне().ДлительныеОперации.ОтменитьВыполнениеЗадания(), и фоновый процесс на сервере принудительно обрывается.Этот способ позволяет загружать данные в разы быстрее (так как работа идет непосредственно на сервере в фоне) и предоставляет пользователю современный, понятный интерфейс.
Если переписывать логику под фоновые задания сейчас нет времени, а прерывать цикл на клиенте все-таки нужно, рассмотрим простейший встроенный механизм платформы — ОбработкаПрерыванияПользователя().
Этот метод проверяет, не нажал ли пользователь сочетание клавиш Ctrl+Break (или Ctrl+Cancel). Если нажал — вызывается исключение и выполнение кода прекращается.
Посмотрим на пример использования:
&НаКлиенте
Процедура ЗагрузитьДанныеИзЭксель()
Для Каждого СтрокаПрайса Из ТаблицаЭксельНаФорме Цикл
// Вызываем метод на каждой итерации.
// Он не тормозит работу, но проверяет, не было ли команды прерывания.
ОбработкаПрерыванияПользователя();
// ... алгоритм обработки строки ...
КонецЦикла;
КонецПроцедуры
Преимущества этого способа: мы избавляемся от раздражающих диалоговых окон ("Продолжить?"), код выполняется без интерактивных пауз до самого конца. Нам достаточно лишь проинструктировать пользователя: "Если хотите остановить загрузку досрочно — нажмите Ctrl+Break на клавиатуре". Важно помнить, что этот метод работает не во всех клиентских контекстах, но в обычных клиентских процедурах формы он отрабатывает корректно.
Подведем итог. Если вы разрабатываете загрузку данных в современных версиях 1С, избегайте диалоговых окон внутри массивных циклов. Если требуется прерывание:
Асинх/Ждать с асинхронным диалогом (доступно с 8.3.18).ОбработкаПрерыванияПользователя() и научите операторов использовать горячие клавиши.