Почему метод Сообщить() в 1С срабатывает только в конце выполнения кода и как это исправить?

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

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

Выясняем причину: почему сообщения «копятся»?

Разберем внутреннюю механику работы платформы «1С:Предприятие 8». Основная причина задержки кроется в архитектуре клиентского приложения. В управляемом приложении поток графического интерфейса (GUI) и поток выполнения программного кода на языке 1С — это, по сути, один и тот же поток.

Проанализируем ситуацию: когда вы запускаете тяжелый цикл Для сч = 0 По 10000 Цикл, процессор полностью занят вычислениями встроенного языка. Поскольку поток один, у платформы просто не остается ресурсов на то, чтобы перерисовать окно сообщений или обновить форму. Метод Сообщить() в данном случае не выводит текст на экран мгновенно, а помещает его в специальный буфер (массив накопления). Этот буфер «сбрасывается» на экран только в тот момент, когда выполнение кода завершается и управление возвращается платформе для обновления интерфейса.

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

Решение 1: Использование метода Состояние()

Если нам нужно просто информировать пользователя о ходе процесса (например, «Обработано 500 из 1000 строк»), самым простым и эффективным способом будет использование метода Состояние(). В отличие от окна сообщений, панель состояния (строка внизу экрана или отдельное окно прогресса) обновляется платформой более приоритетно.

Рассмотрим пример кода:


Для Счетчик = 1 По ОбщееКоличество Цикл
    // Какая-то полезная нагрузка
    Процент = Окр(Счетчик / ОбщееКоличество * 100);
    Состояние("Выполняется обработка данных...", Процент, "Подождите завершения...");
КонецЦикла;

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

Решение 2: Реквизит формы «Поле текстового документа»

Как было замечено в ходе обсуждения на форуме, существует отличный лайфхак для создания интерактивного лога в реальном времени. Если мы не можем заставить стандартное окно сообщений обновляться, мы можем создать свое собственное прямо на форме.

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

  1. Добавим на форму новый реквизит, например, с именем ТекстЛога и типом Строка (неограниченной длины).
  2. Вынесем его на форму и установим вид элемента — Поле текстового документа.
  3. В цикле будем добавлять новые строки в этот реквизит.

Пример реализации:


&НаКлиенте
Процедура ВыполнитьДлительнуюОперацию()
    ТекстЛога = "Начало обработки..." + Символы.ПС;
    Для сч = 1 По 100 Цикл
        // Имитация работы
        ТекстЛога = ТекстЛога + "Обработка итерации №" + Строка(сч) + Символы.ПС;
        
        // Магия обновления интерфейса
        ЭтаФорма.ОбновитьОтображениеДанных(); 
    КонецЦикла;
    ТекстЛога = ТекстЛога + "Завершено!";
КонецПроцедуры

При использовании Поля текстового документа и метода ОбновитьОтображениеДанных(), текст будет появляться в поле синхронно с ходом цикла, что решает проблему «замирания» интерфейса.

Решение 3: Использование метода ПоказатьОповещениеПользователя()

Еще один вариант — выводить всплывающие окна («тосты»), которые появляются в углу экрана. Метод ПоказатьОповещениеПользователя() работает асинхронно и не блокирует выполнение кода.

Однако стоит помнить о здравом смысле: если вызвать этот метод 1000 раз в секунду, интерфейс пользователя превратится в хаос, а система может начать тормозить. Этот метод хорош для ключевых этапов (например, «Загрузка файла завершена», «Найдена критическая ошибка»).

Решение 4: Разделение на порции через Обработчик Ожидания

Это наиболее профессиональный подход с точки зрения проектирования интерфейсов. Суть заключается в том, чтобы не выполнять весь цикл целиком, а разбить его на «кванты» времени. Мы выполняем, например, 50 итераций, после чего прерываемся и даем платформе «вдохнуть» (обновить интерфейс), а затем запускаем следующую порцию через 0.1 секунды.

Проанализируем примерную схему:

  1. Создаем процедуру-обработчик, которая выполняет часть работы.
  2. В конце процедуры проверяем, не закончена ли вся работа.
  3. Если работа осталась, вызываем ПодключитьОбработчикОжидания("ИмяПроцедуры", 0.1, Истина).

В моменты этих микро-пауз платформа успеет вывести все накопленные сообщения Сообщить() на экран, и пользователь будет видеть прогресс в реальном времени.

Решение 5: Механизм длительных операций (БСП)

В современных конфигурациях (ЕРП, УТ 11, БСП) крайне не рекомендуется выполнять тяжелые вычисления непосредственно в клиентском потоке. Правильный путь — запуск фонового задания на сервере.

Выясним, как это работает в типовых решениях:

Подведем итоги

Мы выяснили, что «зависание» сообщений — это не баг, а особенность однопоточной архитектуры клиента 1С. Для решения проблемы мы можем:

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

← На главную