К статье
Практический материал

Разработка и Конфигурация · 12 мин

Как остановить выполнение цикла в 1С

Как остановить цикл в 1С: операторы Прервать, Продолжить и Возврат, выход из вложенных циклов, обработка исключений и типичные ошибки с примерами кода.

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

Выбор оператора зависит от задачи: нужно ли выйти только из цикла и продолжить выполнение кода после него, выйти из всей процедуры целиком или просто пропустить часть элементов коллекции. Неправильный выбор приводит к лишним проходам по большим массивам данных, потере производительности и логическим ошибкам, которые трудно отловить при тестировании.

Ниже разобраны все способы остановки цикла, их поведение во вложенных конструкциях, работа с исключениями и типичные ошибки, которые допускают разработчики при прерывании итераций.

Оператор «Прервать» — основной способ остановки цикла

Оператор Прервать немедленно прекращает выполнение цикла любого типа: Для ... Цикл, Для Каждого ... Цикл и Пока ... Цикл. Управление передаётся на первую строку кода после ключевого слова КонецЦикла. Остальные итерации не выполняются, что особенно важно при обходе больших таблиц значений или результатов запросов.

Типовой сценарий — поиск элемента в коллекции. Как только нужный элемент найден, продолжать обход бессмысленно:

НайденныйСотрудник = Неопределено;

Для Каждого Сотрудник Из ТаблицаСотрудников Цикл

Если Сотрудник.ТабельныйНомер = ИскомыйНомер Тогда

НайденныйСотрудник = Сотрудник;

Прервать;

КонецЕсли;

КонецЦикла;

Без Прервать цикл прошёл бы все строки таблицы даже после того, как результат уже получен. На таблице в десятки тысяч строк это заметная и бесполезная трата времени. Признак правильного применения оператора — после цикла переменная содержит первый подходящий элемент, а обход завершился ровно на нём.

Оператор «Продолжить» — пропуск итерации без остановки цикла

Оператор Продолжить не останавливает цикл, а досрочно завершает текущую итерацию: всё, что написано после него в теле цикла, пропускается, и начинается следующий проход. Для цикла Для ... Цикл при этом выполняется инкремент счётчика, для Для Каждого — переход к следующему элементу коллекции.

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

Для Каждого Строка Из ТаблицаТоваров Цикл

Если Строка.Количество = 0 Тогда

Продолжить; // строки без количества не обрабатываем

КонецЕсли;

Если Не ЗначениеЗаполнено(Строка.Номенклатура) Тогда

Продолжить;

КонецЕсли;

// основная обработка строки

СформироватьДвижения(Строка);

КонецЦикла;

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

Оператор «Возврат» — остановка цикла вместе с процедурой

Когда после завершения цикла в процедуре делать больше нечего, вместо связки «Прервать + код после цикла» используют Возврат. Он прекращает выполнение не только цикла, но и всей процедуры или функции, в которой находится. В функции оператор обязан сопровождаться возвращаемым значением: Возврат Результат;.

Функция НайтиДокументПоНомеру(Номер)

Для Каждого Документ Из СписокДокументов Цикл

Если Документ.Номер = Номер Тогда

Возврат Документ; // выход из цикла и функции одновременно

КонецЕсли;

КонецЦикла;

Возврат Неопределено; // ничего не нашли

КонецФункции

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

Сравнение вариантов

Прервать

Останавливает только текущий цикл, код после КонецЦикла выполняется. Подходит для поиска и досрочного выхода из обхода.

Продолжить

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

Возврат

Завершает цикл и всю процедуру или функцию. Подходит, когда после цикла осмысленного кода нет.

ВызватьИсключение

Прерывает выполнение с ошибкой, разматывает весь стек вызовов. Подходит только для аварийных ситуаций.

Выход из вложенных циклов

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

Найдено = Ложь;

Для Каждого Заказ Из ТаблицаЗаказов Цикл

Для Каждого СтрокаЗаказа Из Заказ.Товары Цикл

Если СтрокаЗаказа.Номенклатура = ИскомаяНоменклатура Тогда

Найдено = Истина;

Прервать; // выход из внутреннего цикла

КонецЕсли;

КонецЦикла;

Если Найдено Тогда

Прервать; // выход из внешнего цикла

КонецЕсли;

КонецЦикла;

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

Маршрут решения

Как выбрать способ выхода

Нужно выйти из одного цикла и продолжить код после негоИспользуйте Прервать в точке, где условие выполнено
Часть элементов коллекции не нужно обрабатыватьПоставьте Продолжить с проверкой в начале итерации
После цикла в процедуре нет полезного кодаИспользуйте Возврат вместо Прервать
Циклы вложены на два и более уровнейВведите флаг-переменную или вынесите обход в отдельную функцию с Возврат
Продолжение работы бессмысленно или опасно для данныхВызовите исключение и зафиксируйте транзакцию откатом

Аварийная остановка через исключения

Если внутри цикла обнаружена ситуация, при которой дальнейшая работа невозможна или опасна — например, нарушена целостность данных, — используют ВызватьИсключение. Исключение прерывает не только цикл, но и всю цепочку вызовов до ближайшего блока Попытка ... Исключение ... КонецПопытки. Если обработчика нет, выполнение кода завершается с сообщением об ошибке.

Для Каждого Строка Из ТаблицаОплат Цикл

Если Строка.Сумма < 0 Тогда

ВызватьИсключение "Обнаружена отрицательная сумма оплаты. Обработка остановлена.";

КонецЕсли;

// проведение оплаты

КонецЦикла;

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

Бесконечные циклы и их принудительная остановка

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

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

СчетчикИтераций = 0;

Пока Истина Цикл

СчетчикИтераций = СчетчикИтераций + 1;

Если СчетчикИтераций > 100000 Тогда

ВызватьИсключение "Превышено допустимое число итераций цикла.";

КонецЕсли;

// основная логика с условием выхода через Прервать

КонецЦикла;

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

Типичные ошибки
01
Ожидание, что Прервать остановит вложенный цикл целиком — внешний цикл продолжает работу, итоговый результат неверный
02
Изменение коллекции внутри цикла Для Каждого (удаление элементов) — обход пропускает элементы или падает с ошибкой; удаляйте по индексу с конца или собирайте элементы в отдельный список
03
Использование ВызватьИсключение для обычной фильтрации — код замедляется, а реальные ошибки тонут в штатных
04
Цикл Пока без гарантированного выхода — зависание сеанса и нагрузка на сервер
05
Прервать после записи данных без транзакции — в базе остаются частично обработанные данные

Проверка и отладка остановки цикла

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

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

Контрольные точки

Как проверить результат

Поведение после Прервать
Норма

Выполняется первая строка после КонецЦикла, счётчик или элемент соответствует найденному

Тревожный признак

Цикл обходит все элементы коллекции до конца

Вложенные циклы
Норма

После срабатывания условия остановлены оба уровня обхода

Тревожный признак

Внешний цикл продолжает итерации после выхода из внутреннего

Цикл Пока
Норма

Количество итераций конечно и предсказуемо, есть ограничитель

Тревожный признак

Сеанс зависает, растёт нагрузка на процессор

Запись данных при прерывании
Норма

При ошибке транзакция откачена, данных в базе нет

Тревожный признак

Часть документов записана, часть нет

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

Чем Прервать отличается от Продолжить?

Прервать полностью завершает цикл: ни одна итерация больше не выполняется, управление переходит к коду после КонецЦикла. Продолжить завершает только текущую итерацию и запускает следующую — цикл продолжает работать, пока не закончится коллекция или не станет ложным условие.

Как выйти сразу из двух вложенных циклов?

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

Можно ли остановить цикл обхода результата запроса?

Да, выборка из результата запроса обходится обычным циклом Пока Выборка.Следующий() Цикл, и оператор Прервать работает в нём так же. Однако если нужно ограничить число строк, эффективнее использовать конструкцию ПЕРВЫЕ N в тексте запроса — сервер вернёт меньше данных.

Что делать, если цикл завис и сеанс не отвечает?

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

Можно ли удалять элементы коллекции внутри цикла Для Каждого?

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

Останавливает ли Возврат цикл в вызывающей процедуре?

Нет. Возврат завершает только ту процедуру или функцию, в которой он выполнен. Вызывающий код продолжит работу со следующей строки после вызова. Если нужно остановить всю цепочку, каждый уровень должен анализировать возвращённое значение и сам решать о выходе.

Итог

Что важно запомнить

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