Программная пауза в 1С: все способы и их риски

· 9 мин

Содержание

Пауза на клиенте делается глобальной процедурой Ждать(Секунды) — например, Ждать(2) остановит выполнение на две секунды. На сервере этой процедуры нет: там задержку организуют фоновым заданием, таймаутом внешнего соединения или (в крайнем случае) внешней компонентой. Если нужно не заморозить код, а выполнить что-то позже, не блокируя интерфейс, — это ПодключитьОбработчикОжидания.

Ниже разберём каждый способ: где он работает, какой у него побочный эффект и когда его применять. Сразу предупреждение: «подождать циклом» — самый частый и самый вредный вариант, он грузит процессор впустую. К нему вернёмся отдельно.

Выбрать подходящий механизм под конкретную задачу поможет быстрый разбор:

Где и зачем нужна пауза?

Пауза на клиенте: процедура Ждать

Самый прямой способ сделать задержку в 1С на клиенте — глобальная процедура Ждать:

Ждать(3); // остановить выполнение на 3 секунды

Полная форма вызова — Ждать(<Интервал>, <Интерактивно>):

  • 🕒 Интервал — число секунд. Допускаются дробные значения, то есть Ждать(0.5) даст полсекунды.
  • 👁 Интерактивно — булево, по умолчанию Ложь. Если передать Истина, система покажет пользователю индикатор ожидания и даст возможность прервать операцию.

Процедура работает только в клиентском контексте: тонкий клиент, веб-клиент, толстый клиент в режиме управляемого приложения. На сервере и во внешнем соединении её нет — компилятор выдаст ошибку.

Ждать блокирует поток выполнения полностью. Пока идёт пауза, форма не реагирует на действия пользователя: окно «подвисает». Для коротких технических пауз это терпимо, для ожидания в несколько секунд во время работы оператора — нет.

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

Не используйте Ждать внутри транзакции или в серверных вызовах, которые ждёт пользователь: длинная пауза удержит блокировки и повиснет на всех.

Не путайте два разных Ждать. Есть глобальная процедура Ждать(Секунды) — та самая блокирующая пауза из этого раздела. И есть оператор Ждать в асинхронных методах (Асинх Функция ... Ждать ...), который появился в платформе для работы без вложенных обработчиков оповещения. Второй — не про паузу: он не «ждёт N секунд», а дожидается результата асинхронной операции и возвращает управление, не морозя клиент. Если вам нужна именно задержка во времени — это процедура с числовым аргументом.

Как подождать, не морозя интерфейс

Если задача — «выполнить что-то через несколько секунд», а не «остановить код здесь», блокирующая пауза вредна. Правильный инструмент — обработчик ожидания:

// где-то в модуле формы
ПодключитьОбработчикОжидания("ПослеПаузы", 3, Истина);

&НаКлиенте
Процедура ПослеПаузы()
    // этот код выполнится через 3 секунды
    ОбновитьДанныеНаФорме();
КонецПроцедуры

Параметры — ПодключитьОбработчикОжидания(<ИмяПроцедуры>, <Интервал>, <Однократно>):

  • Имя клиентской процедуры без параметров (строкой).
  • Интервал в секундах. Минимум — 1 секунда, дробные значения меньше единицы не сработают.
  • Однократно = Истина — вызвать один раз. Если Ложь или не указано, процедура будет срабатывать по кругу, пока её не отключат.

Ключевая разница с Ждать: обработчик не блокирует форму. Пользователь продолжает работать, а через заданный интервал платформа сама вызовет вашу процедуру. Это способ сделать «задержку» перед повторной попыткой, опросом статуса или автообновлением списка.

Отключается обработчик симметрично:

ОтключитьОбработчикОжидания("ПослеПаузы");

Для периодического опроса (например, «каждые 5 секунд проверяй, готов ли отчёт») обработчик ожидания с Однократно = Ложь — штатное решение. Не делайте опрос циклом с Ждать — это заморозит клиент на всё время ожидания.

Пауза на сервере: почему Ждать недоступен

На сервере процедуры Ждать нет по замыслу платформы. Серверный код выполняется в рабочем процессе кластера и обслуживает много сеансов; заморозить его «на подождать» — значит занять рабочий процесс вхолостую и ухудшить работу всем. Поэтому прямой паузы на сервере платформа не даёт.

Когда задержка на сервере всё-таки нужна, применяют один из обходных путей:

  1. Внешняя компонента с методом задержки (на базе системного вызова Sleep). Самый корректный серверный вариант: компонента на Native API вызывает ожидание средствами ОС, не загружая процессор. Минус — её нужно разработать, собрать и зарегистрировать.
  2. Системная команда ОС. Запуск через ЗапуститьПриложение синхронной команды, которая сама делает паузу: на Windows это timeout /t 5 /nobreak, на Linux — sleep 5. Выглядит это так:
// Windows, синхронный запуск (ждём завершения команды)
ЗапуститьПриложение("cmd /c timeout /t 5 /nobreak", , Истина);

Третий параметр Истина означает «дождаться завершения». Способ рабочий, но требует права на запуск приложений на сервере, зависит от ОС и всё равно блокирует рабочий процесс на время паузы. Используйте его только когда внешнюю компоненту собрать негде. 3. Цикл по времени — busy wait. Простой, но вредный способ, разбираем ниже отдельно.

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

Отложенное выполнение: фоновые и регламентные задания

Если смысл задержки — «сделать это потом» или «вынести долгую операцию из основного потока», паузы не нужны вовсе. Нужны задания.

Фоновое задание запускает метод в отдельном сеансе, не блокируя тот, что его инициировал:

Параметры = Новый Массив;
Параметры.Добавить(Ссылка);
ФоновыеЗадания.Выполнить("ОбщийМодуль.ДлиннаяОперация", Параметры);

Запускается оно сразу, а не «через N минут». Инициатор при этом продолжает работу и может периодически проверять состояние задания методами объекта ФоновоеЗадание (например, через ПолучитьФоновыеЗадания с отбором). Это и есть «задержка без задержки»: тяжёлый код уходит в фон, а интерфейс не ждёт.

Регламентное задание — для запуска именно по времени. У него есть расписание (Расписание), где задаются периодичность, время старта, дни недели. Если надо выполнить код «через час» или «каждую ночь в 2:00» — это регламентное задание, а не пауза в коде.

В типовых конфигурациях на БСП для фоновых операций есть подсистема «Длительные операции»: она упаковывает запуск в фоне, прогресс и получение результата. Если конфигурация типовая — используйте её вместо ручной работы с ФоновыеЗадания.

Важно про отладку и окружение:

  • Фоновые задания не запускаются в файловой базе, если нет активного клиентского сеанса, — учитывайте при тестировании.
  • Параметры метода должны быть сериализуемыми: ссылки, примитивы, структуры из них. Мутабельные объекты формы туда не передать.

Задержка циклом и чем она опасна

Самый частый «народный» способ сделать паузу — крутить пустой цикл, пока не пройдёт нужное время:

// ТАК ДЕЛАТЬ НЕ НАДО
Старт = ТекущаяУниверсальнаяДатаВМиллисекундах();
Пока ТекущаяУниверсальнаяДатаВМиллисекундах() - Старт < 5000 Цикл
    // пусто — просто ждём 5 секунд
КонецЦикла;

Работает, но ценой того, что ядро процессора на всё время паузы загружено на 100% впустую. Это busy wait — активное ожидание. Чем он плох:

  • 🔥 Нагрузка на CPU. Один такой цикл съедает ядро целиком. Несколько сеансов с таким кодом кладут сервер.
  • 🧊 Заморозка. На клиенте форма виснет так же, как при Ждать, но ещё и греет процессор. На сервере — занимает рабочий процесс.
  • ⏱ Неточность. Реальная пауза зависит от загрузки машины и может «уехать».

Если альтернатив действительно нет и пауза нужна здесь и сейчас, на клиенте берите Ждать (оно отдаёт ядро системе, а не жжёт его), а на сервере — внешнюю компоненту или системную команду. Пустой цикл — последний вариант, которого стоит избегать.

Отдельно опасен цикл с обращением к базе или сервису «для проверки» на каждой итерации без паузы между запросами. Это не ожидание, а DDoS собственного сервера: тысячи запросов в секунду. Между проверками всегда должен быть интервал.

Таймауты при работе с внешними сервисами

Часто за «задержкой» на самом деле скрывается зависание на внешнем сервисе: код ушёл за данными по HTTP и ждёт ответа, которого нет. Решение здесь не пауза, а таймаут — ограничение времени ожидания.

У объекта HTTPСоединение за это отвечает свойство и параметр конструктора Таймаут (в секундах):

Соединение = Новый HTTPСоединение(
    "api.example.ru", 443, , , , 10, Новый ЗащищённоеСоединениеOpenSSL());

Здесь 10 — максимум 10 секунд на операцию. Если сервис не ответил, вы получите ошибку и сможете её обработать, а не повиснете навсегда.

  • 🌐 Всегда задавайте таймаут при обращении к внешним сервисам. По умолчанию ожидание может быть неограниченным, и один медленный ответ подвесит сеанс.
  • 🔁 Для повторных попыток при сбое делайте паузу между ними — но на клиенте через обработчик ожидания, а в фоновом задании через короткую серверную задержку или просто следующий запуск по расписанию. Полезный приём — наращивать паузу: первая попытка через 2 секунды, вторая через 4, третья через 8. Так вы не заваливаете сервис запросами, пока он восстанавливается.
  • 🔌 У веб-сервисных прокси (WSОпределения, WSПрокси) таймаут задаётся аналогично в параметрах получения определений.

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

Как отладить и замерить код с задержкой

Код с паузами и фоновыми заданиями отлаживается сложнее обычного — часть выполняется не там, где вы его запустили.

Замер фактической паузы. Проверить, сколько реально ждал код, проще всего по времени:

Старт = ТекущаяУниверсальнаяДатаВМиллисекундах();
Ждать(2);
Сообщить("Пауза заняла " + (ТекущаяУниверсальнаяДатаВМиллисекундах() - Старт) + " мс");

Так видно расхождение между запрошенным и реальным интервалом.

Отладка фоновых заданий. Чтобы точки останова срабатывали в коде, который выполняется в фоне, отладку рабочих процессов нужно разрешить:

  • В клиент-серверной базе — включить отладку по протоколу (HTTP) и разрешить отладку фоновых заданий в настройках кластера/публикации.
  • В конфигураторе — в предмете отладки отметить тип «Фоновые задания», иначе точки останова в них просто не остановят выполнение.

Если точка останова в фоновом задании не срабатывает — почти всегда причина в том, что отладка фоновых заданий не включена, а не в ошибке кода. Проверьте настройку в первую очередь.

Визуализация прогресса. Для долгих операций показывайте пользователю состояние, а не пустое ожидание: индикатор через Состояние(...) на сервере или обновление поля на форме по обработчику ожидания. Так «задержка» перестаёт выглядеть зависанием.

Для точного профилирования (где именно код тратит время) используйте замер производительности в конфигураторе — он покажет длительность каждой строки, включая паузы и обращения к сервисам.

Частые вопросы

Почему процедура Ждать не компилируется на сервере?
Ждать существует только в клиентском контексте. На сервере паузы делают через фоновое задание, таймаут внешнего соединения или внешнюю компоненту. Если вам понадобилась серверная пауза — скорее всего, задачу стоит решить отложенным запуском, а не задержкой.
Можно ли сделать паузу меньше секунды?
На клиенте — да: Ждать(0.3) остановит на 0,3 секунды, интервал может быть дробным. А вот у обработчика ожидания минимум — целая 1 секунда, меньше задать нельзя.
Как сделать задержку, не замораживая интерфейс пользователя?
Используйте ПодключитьОбработчикОжидания: процедура вызовется через заданное число секунд, а форма всё это время остаётся активной. Блокирующий Ждать для ожидания во время работы оператора не подходит.
Фоновое задание стартует сразу — как запустить его позже?
Для запуска по времени используйте регламентное задание с расписанием. Фоновое задание предназначено для немедленного запуска в отдельном сеансе, отложенного старта у него нет.
Как избежать зависания при обращении к внешнему сервису?
Задавайте свойство Таймаут у HTTPСоединения (в секундах). Тогда при отсутствии ответа код получит ошибку через заданное время, а не повиснет. Это надёжнее любой самодельной паузы.