Когда формирование отчета занимает значительное время (от нескольких минут и более), пользователи часто сталкиваются с эффектом «зависания» интерфейса. В этот момент непонятно, работает ли программа или произошел системный сбой. Для решения этой проблемы разработчику необходимо предоставить пользователю визуальную обратную связь: отображать шкалу прогресса (прогресс-бар), выводить текстовые сообщения о текущем этапе выполнения или осуществлять постепенную (порционную) отрисовку данных на экране.
В этой статье мы подробно разберем четыре практических метода реализации обратной связи при выполнении длительных операций в 1С:Предприятие, а также затронем критически важные аспекты оптимизации производительности отчетов.
---
Если ваша конфигурация разработана на базе Библиотеки стандартных подсистем (БСП), то изобретать собственный велосипед не нужно. В БСП встроен мощный и надежный механизм асинхронного выполнения серверного кода с поддержкой трансляции прогресса на клиентскую форму.
Рассмотрим по шагам, как настроить этот механизм для вашего отчета.
Шаг 1. Серверная часть (в фоновом задании)
В процедуре, которая запускается в фоновом задании, мы должны периодически отправлять информацию о текущем состоянии процесса. Для этого используется метод ДлительныеОперации.СообщитьПрогресс(). Важно помнить правило: не стоит перегружать систему слишком частыми вызовами. Оптимально сообщать о прогрессе не чаще одного раза в 3 секунды.
Процедура СформироватьОтчетНаСервере(ПараметрыОтчета, АдресРезультата) Экспорт
ДанныеДляВыгрузки = ПолучитьВыборкуДанных(ПараметрыОтчета);
ВсегоЗаписей = ДанныеДляВыгрузки.Количество();
Для Индекс = 0 По ВсегоЗаписей - 1 Цикл
// Выполняем расчеты и заполняем строки отчета
ОбработатьСтрокуДанных(ДанныеДляВыгрузки[Индекс]);
// Каждые 5% выполняем отправку прогресса на клиент
Если Индекс % (Макс(1, Цел(ВсегоЗаписей / 20))) = 0 Тогда
Процент = Цел((Индекс + 1) / ВсегоЗаписей * 100);
ТекстСостояния = СтрШаблон("Обработано строк: %1 из %2", Индекс + 1, ВсегоЗаписей);
// Передаем данные в БСП
ДлительныеОперации.СообщитьПрогресс(Процент, ТекстСостояния);
КонецЕсли;
КонецЦикла;
// Помещаем финальный результат во временное хранилище
ПоместитьВоВременноеХранилище(ДанныеДляВыгрузки, АдресРезультата);
КонецПроцедуры
Шаг 2. Клиентская часть (на управляемой форме)
На форме отчета нам понадобится запустить фоновое задание и подключить обработчик ожидания, который будет считывать процент выполнения и обновлять элемент формы типа «Поле индикатора».
&НаКлиенте
Процедура СформироватьОтчет(Команда)
// Подготавливаем параметры для БСП
ПараметрыВыполнения = ДлительныеОперацииКлиент.ПараметрыВыполнения(ЭтотОбъект);
ПараметрыВыполнения.ВыводитьПрогрессВыполнения = Истина;
ПараметрыВыполнения.ОповещениеОПрогрессеВыполнения = Новый ОписаниеОповещения("ОбработатьПрогрессВыполнения", ЭтотОбъект);
// Запускаем асинхронное фоновое задание
ИмяЭкспортируемойПроцедуры = "ИмяОбщегоМодуля.СформироватьОтчетНаСервере";
РезультатЗапуска = ДлительныеОперацииВызватьСервер.ЗапуститьВыполнение(ИмяЭкспортируемойПроцедуры, ПараметрыВыполнения);
// Ожидаем завершения с обновлением прогресса на форме
ПараметрыОжидания = ДлительныеОперацииКлиент.ПараметрыОжидания(ЭтотОбъект);
ДлительныеОперацииКлиент.ОжидатьЗавершение(РезультатЗапуска.ИдентификаторЗадания, ПараметрыОжидания);
КонецПроцедуры
&НаКлиенте
Процедура ОбработатьПрогрессВыполнения(Прогресс, ДополнительныеПараметры) Экспорт
Если Прогресс = Неопределено Тогда
Возврат;
КонецЕсли;
// Обновляем реквизиты формы, связанные с визуальными элементами
ПроцентВыполнения = Прогресс.Процент;
ТекстСостояния = Прогресс.Текст;
КонецПроцедуры
---
Если вы работаете в самописной конфигурации или старых версиях баз, где БСП отсутствует, аналогичный механизм можно спроектировать вручную с помощью фоновых заданий и чтения сообщений пользователя.
Принцип прост: фоновое задание в процессе работы пишет текстовые сообщения через метод Сообщить(), а клиент раз в пару секунд считывает их и парсит для вывода на экран.
Разберем программную реализацию этой схемы:
// Код внутри фонового задания на сервере
Процедура ВыполнитьДлительныйРасчет() Экспорт
Для Шаг = 1 По 10 Цикл
// Имитация длительной работы
ФизическаяПауза(1);
// Отправляем структурированное сообщение для клиента
Сообщить(СтрШаблон("ПРОГРЕСС|%1|Выполнение шага %2 из 10", Шаг * 10, Шаг));
КонецЦикла;
КонецПроцедуры
На клиенте мы запускаем обработчик ожидания, который будет опрашивать наше фоновое задание:
&НаКлиенте
Перем ИдентификаторЗадания;
&НаКлиенте
Процедура ЗапуститьРасчет()
ИдентификаторЗадания = ЗапуститьЗаданиеНаСервере();
ПодключитьОбработчикОжидания("ПроверитьСтатусЗадания", 1);
КонецПроцедуры
&НаКлиенте
Процедура ПроверитьСтатусЗадания()
ДанныеЗадания = ПолучитьИнформациюОЗадании(ИдентификаторЗадания);
// Считываем сообщения, накопленные фоновым заданием
МассивСообщений = ДанныеЗадания.Сообщения;
Для Каждого Сообщение Из МассивСообщений Цикл
Если Найти(Сообщение.Текст, "ПРОГРЕСС|") = 1 Тогда
ЧастиСтроки = СтрРазделить(Сообщение.Текст, "|");
ПроцентВыполнения = Число(ЧастиСтроки[1]);
ТекущийСтатус = ЧастиСтроки[2];
КонецЕсли;
КонецЦикла;
Если ДанныеЗадания.Завершено Тогда
ОтключитьОбработчикОжидания("ПроверитьСтатусЗадания");
ПоказатьПредупреждение(, "Расчет успешно завершен!");
КонецЕсли;
КонецПроцедуры
Современный подход (начиная с платформы 8.3.26+): В актуальных версиях платформы появился механизм «Уведомлений клиента». Теперь сервер может отправлять прямые сигналы на клиент через систему взаимодействия без постоянного циклического опроса и использования обработчиков ожидания, что существенно снижает нагрузку на сеть и сервер СУБД.
---
Если ваш отчет построен на Системе компоновки данных (СКД), платформа предоставляет штатный механизм визуализации вывода. Он отображает заполнение шкалы непосредственно в строке состояния окна 1С.
Чтобы задействовать этот функционал при программном выводе отчета СКД, выполним следующие шаги:
ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент.ОтображатьПроцентВывода в значение Истина.Посмотрим на пример практической реализации:
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки);
ТабличныйДок = Новый ТабличныйДокумент;
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(ТабличныйДок);
// Включаем штатное отображение процентов
ПроцессорВывода.ОтображатьПроцентВывода = Истина;
ПроцессорВывода.НачатьВывод();
ВсегоЭлементов = 10000; // Примерное количество строк
ТекущийЭлемент = 0;
Пока Истина Цикл
ЭлементРезультата = ПроцессорКомпоновки.Следующий();
Если ЭлементРезультата = Неопределено Тогда
Прервать;
КонецЕсли;
ПроцессорВывода.ВывестиЭлемент(ЭлементРезультата);
ТекущийЭлемент = ТекущийЭлемент + 1;
// Передаем процент выполнения в платформу для отображения в строке состояния
ЭлементРезультата.ПроцентВывода = Цел((ТекущийЭлемент / ВсегоЭлементов) * 100);
КонецЦикла;
ПроцессорВывода.ЗакончитьВывод();
---
Один из самых частых вопросов разработчиков: «Можно ли сделать так, чтобы строки таблицы появлялись на экране пользователя сразу по мере их формирования на сервере?»
При стандартном синхронном вызове это технически невозможно, так как контекст выполнения переходит на сервер, а клиентский интерфейс блокируется («замораживается») в ожидании возврата управления. Однако эту задачу можно элегантно решить через асинхронную модель работы с Временным хранилищем.
Архитектурная схема решения:
ВременноеХранилище под уникальным ключом-адресом.ТабличногоДокумента на форме.В результате пользователь наблюдает плавную и живую «дорисовку» отчета на экране, сохраняя при этом полную отзывчивость интерфейса программы.
---
Каким бы красивым ни был ваш прогресс-бар, лучшим решением всегда будет оптимизация логики работы отчета. Помните золотое правило разработки в 1С: типовые отчеты не должны формироваться дольше 30-40 секунд (за исключением тяжелых годовых регламентированных расчетов на слабых серверах).
Если ваш отчет выполняется слишком долго, проанализируйте следующие факторы:
Для или Пока. Перепишите алгоритм так, чтобы получить все необходимые данные одним пакетным запросом во временные таблицы, а затем быстро обойти готовую выборку.ОтображатьДанныеРасшифровки = Ложь у вашего Табличного документа. Без необходимости кэширования расшифровки вывод отчета на экран ускорится в разы, так как платформа освободится от колоссальной нагрузки по отрисовке скрытых метаданных.Совмещая грамотную оптимизацию запросов с современными асинхронными методами информирования о прогрессе, мы можем создавать быстрые, удобные и отзывчивые интерфейсы, которые гарантируют комфортную работу пользователей в любых прикладных решениях 1С.