Пауза и задержка выполнения кода в 1С 8.3

· 9 мин

Содержание

В 1С нет глобальной команды Sleep, которая просто остановила бы код на N секунд, — и это сделано намеренно. Клиентский код выполняется в один поток: блокирующая пауза заморозит интерфейс, а на тонком и веб-клиенте может оборвать сеанс. Поэтому «паузу» в 1С делают одним из трёх способов в зависимости от того, что именно нужно.

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

Почему готовой команды Sleep нет и чем её заменить

Платформа 1С:Предприятие 8.3 событийная. Форма реагирует на действия пользователя, фоновые процессы живут отдельно, а длинная блокировка потока ломает эту модель. Жёсткое «усни на 5 секунд» в клиенте приводит к зависшему окну и сообщению «Приложение не отвечает».

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

Правило простое: нужна задержка на клиенте — думайте не «как усыпить код», а «какую процедуру запустить по таймеру». Это и есть идеология 1С.

В платформе 8.3 с номером не ниже 8.3.18 для ожидания результата асинхронных операций появился более аккуратный приём — асинхронные методы и ключевое слово Ждать. Оно приостанавливает выполнение асинхронной функции до готовности результата, но не блокирует клиента: пока функция «ждёт», интерфейс остаётся живым. Если ваша конфигурация работает на такой платформе, это читается проще, чем цепочки оповещений. На более ранних сборках остаётся классический обработчик ожидания — его и разберём первым, он доступен везде.

Обработчик ожидания: пауза без заморозки клиента

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

Синтаксис:

ПодключитьОбработчикОжидания(<ИмяПроцедуры>, <Интервал>, <Однократно>);
  • ИмяПроцедуры — имя экспортной процедуры без параметров (в модуле формы или модуле команды);
  • Интервал — время до вызова в секундах, допустимо дробное значение;
  • Однократно — если Истина, процедура сработает один раз и обработчик отключится сам.

Пример: показать сообщение через 3 секунды после открытия формы.

&НаКлиенте
Процедура ПриОткрытии(Отказ)
    ПодключитьОбработчикОжидания("ПоказатьПодсказку", 3, Истина);
КонецПроцедуры

&НаКлиенте
Процедура ПоказатьПодсказку()
    Сообщить("Прошло 3 секунды с момента открытия формы");
КонецПроцедуры

Если обработчик не одноразовый, он будет срабатывать каждые N секунд, пока вы его не остановите:

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

Не задавайте интервал в доли секунды для постоянно повторяющихся обработчиков — частый опрос нагружает клиента и канал связи, особенно в веб-клиенте. Для периодических задач разумный минимум — 1–2 секунды.

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

Жёсткая задержка в толстом клиенте и её риски

Иногда всё же нужна именно блокирующая задержка — например, в обработке, которая запускается в толстом клиенте под Windows и ни с кем не взаимодействует. Готовой функции в платформе нет, но её имитируют через COM-объект операционной системы.

Оболочка = Новый COMObject("WScript.Shell");
// windowStyle = 0 (скрыто), waitOnReturn = Истина (ждать завершения)
Оболочка.Run("timeout /t 5 /nobreak", 0, Истина);

Команда timeout оболочки Windows «спит» 5 секунд, а 1С ждёт её завершения, потому что третий параметр Run равен Истина.

Этот приём блокирует поток целиком: окно 1С перестаёт отвечать на всё время паузы. Он допустим только в толстом клиенте под Windows и только для коротких служебных задержек. В тонком и веб-клиенте так делать нельзя — сеанс может разорваться по таймауту.

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

Как подождать на сервере завершения внешнего процесса

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

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

// Ждём завершения не дольше 30 секунд
Задание.ОжидатьЗавершенияВыполнения(30);

Если Задание.Состояние = СостояниеФоновогоЗадания.Завершено Тогда
    Сообщить("Расчёт выполнен");
КонецЕсли;

Метод ожидания у объекта фонового задания в современных сборках платформы 8.3 называется ОжидатьЗавершенияВыполнения(Таймаут); в более ранних сборках — ОжидатьЗавершения(Таймаут). Таймаут задаётся в секундах; если его не указать, вызов будет ждать до самого конца задания.

Несколько правил, чтобы не наступить на грабли:

  • 🔸 Ожидание нельзя вызывать внутри открытой транзакции — задание в другом сеансе её не увидит, и вы рискуете получить взаимоблокировку.
  • 🔸 После таймаута проверяйте Состояние: задание может быть ещё Активно. Не считайте, что оно завершилось, только потому что вызов вернул управление.
  • 🔸 Busy-wait — цикл с проверкой ТекущаяДатаСеанса() — на сервере не используйте: он намертво занимает рабочий процесс и лицензию, ничего при этом не делая.

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

&НаКлиенте
Процедура ЗапуститьОперацию(Команда)
    ИдентификаторЗадания = ЗапуститьНаСервере(); // вернёт УникальныйИдентификатор задания
    ПодключитьОбработчикОжидания("ПроверитьЗадание", 2);
КонецПроцедуры

&НаКлиенте
Процедура ПроверитьЗадание()
    Если ЗаданиеЗавершеноНаСервере(ИдентификаторЗадания) Тогда
        ОтключитьОбработчикОжидания("ПроверитьЗадание");
        Сообщить("Операция завершена");
    КонецЕсли;
КонецПроцедуры

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

Точки останова: приостановка кода при отладке

Когда «пауза» нужна не в рабочем сценарии, а чтобы остановить код и посмотреть переменные, — это задача отладчика. Точка останова ставит код на паузу на конкретной строке.

Как поставить и запустить отладку в Конфигураторе:

  1. Откройте нужный модуль, встаньте на строку и нажмите F9 — слева появится красный маркер точки останова.
  2. Запустите отладку: меню Отладка → Начать отладку или клавиша F5.
  3. Когда исполнение дойдёт до вашей строки, оно остановится, не выполнив её.

Дальше код «ведут» вручную горячими клавишами:

КлавишаДействие
F5Продолжить выполнение до следующей точки останова
F10Шагнуть через (выполнить строку, не заходя в процедуру)
F11Шагнуть внутрь (зайти в вызываемую процедуру)
Shift+F11Выйти из текущей процедуры
Shift+F9Вычислить выражение под курсором

Полезные приёмы на паузе:

  • 🔹 Точка останова с условием. Щёлкните маркер правой кнопкой и задайте условие — код встанет, только когда оно истинно. Незаменимо, когда цикл делает тысячи итераций, а поймать надо одну.
  • 🔹 Табло. Окно для просмотра и слежения за значениями переменных во время паузы.
  • 🔹 Остановка по ошибке. В меню Отладка можно включить автоматическую остановку в момент возникновения исключения — код сам встанет там, где упал.

Чтобы отладчик вообще подключался к запускаемому сеансу, в Конфигураторе откройте Сервис → Параметры → Запуск 1С:Предприятия → Отладка и включите установку режима разрешения отладки. Тогда сеанс 1С:Предприятия, запущенный из Конфигуратора, будет виден отладчику.

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

COM-объекты и внешние компоненты: ожидание ответа

Отдельная тема — пауза при работе с внешним миром: COM-объектами и внешними компонентами.

Вызовы методов COM-объекта синхронны: 1С сама ждёт, пока метод вернёт управление. Специально «ставить паузу» не нужно — платформа остановится на строке вызова до ответа. Отсюда и подвох: если внешнее приложение зависло, зависнет и ваш сеанс. Поэтому для COM-вызовов, которые могут долго не отвечать, либо выносите их в фоновое задание, либо работайте через толстый клиент, где блокировка интерфейса не оборвёт сеанс.

С внешними компонентами модель другая. Асинхронная компонента не блокирует код, а сообщает о готовности через механизм внешнего события. Вы не «ждёте в цикле», а обрабатываете событие, когда оно придёт:

&НаКлиенте
Процедура ОбработкаВнешнегоСобытия(Источник, Событие, Данные)
    Если Событие = "ГотовоеЗначение" Тогда
        Сообщить("Компонента вернула: " + Данные);
    КонецЕсли;
КонецПроцедуры

Смысл тот же, что и с обработчиком ожидания: вместо остановки потока вы реагируете на сигнал извне. Код не спит — он ждёт события.

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

Задержки внутри циклов и пакетной обработки

Последний частый случай — пауза в длинном цикле: при выгрузке во внешнюю систему, рассылке, обращениях к API «через паузу», чтобы не превысить лимит запросов.

Здесь важно развести две ситуации:

Нужно дать пользователю прервать долгий цикл. На клиенте вставьте в тело цикла вызов:

Для Каждого Строка Из ТаблицаДанных Цикл
    ОбработкаПрерыванияПользователя();
    // ... тяжёлая обработка строки ...
КонецЦикла;

ОбработкаПрерыванияПользователя() проверяет, не нажал ли пользователь прерывание (Ctrl+Break), и аккуратно останавливает выполнение. Это не пауза, но именно её часто ищут, когда цикл «не отдаёт управление».

Нужна задержка между итерациями (например, пауза между запросами к внешнему сервису). Не делайте блокирующий сон внутри серверного цикла — он держит рабочий процесс. Вместо этого:

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

Паузу между запросами к API почти всегда можно заменить правильным размером пакета. Отправляйте данные партиями по расписанию, а не по одному элементу с задержкой — это и быстрее, и не нагружает сервер лишними ожиданиями.

Какой способ паузы выбрать

Короткий ориентир под вашу задачу:

Что именно нужно: отложить, дождаться или остановить код?

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

Есть ли в 1С функция Sleep или Wait, как в других языках?
Глобальной блокирующей функции паузы в платформе нет. Её роль играет ПодключитьОбработчикОжидания на клиенте и ожидание фонового задания на сервере. Блокирующую задержку в толстом клиенте имитируют через COM-объект операционной системы.
Минимальный интервал у обработчика ожидания?
Интервал задаётся в секундах и допускает дробное значение, но для периодических обработчиков не стоит опускаться ниже 1–2 секунд: частый опрос нагружает клиента и канал, а в веб-клиенте мелкие интервалы всё равно работают грубее.
Почему точка останова на сервере не срабатывает?
Для клиент-серверной базы отладку серверного кода нужно разрешить на уровне информационной базы. Пока это не включено, срабатывают только клиентские точки останова, а серверные платформа пропускает.
Как остановить зависший цикл, если паузу не ставил?
Если цикл выполняется на клиенте, добавьте в его тело ОбработкаПрерыванияПользователя() — тогда выполнение можно прервать сочетанием Ctrl+Break. Без этого вызова платформа не проверяет прерывание и цикл не отдаёт управление.
Можно ли ждать фоновое задание прямо в транзакции?
Нет. Ожидание внутри открытой транзакции приводит к тому, что задание в другом сеансе её не видит, и возможна взаимоблокировка. Закройте транзакцию до ожидания или опрашивайте состояние задания по таймеру.