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

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

1С: как прервать цикл «Пока»

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

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

Оператор Прервать немедленно завершает выполнение цикла и передаёт управление на первую строку после КонецЦикла. Оператор Продолжить не завершает цикл, а прерывает текущую итерацию и переходит к проверке условия для следующей. Оба оператора работают одинаково в циклах «Пока» и «Для», поэтому приёмы из этой статьи применимы к любым итеративным конструкциям 1С.

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

Синтаксис цикла «Пока» и оператора Прервать

Базовая конструкция выглядит так: ключевое слово Пока, условие, слово Цикл, тело цикла и КонецЦикла. Условие проверяется перед каждой итерацией — если оно ложно с самого начала, тело не выполнится ни разу.

Счетчик = 0;

Пока Счетчик < 100 Цикл

Счетчик = Счетчик + 1;

// обработка данных

КонецЦикла;

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

Пока Выборка.Следующий() Цикл

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

Сообщить("Обнаружена отрицательная сумма, обработка остановлена");

Прервать;

КонецЕсли;

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

КонецЦикла;

Выход из цикла по условию: типовые сценарии

Поиск первого подходящего элемента

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

НайденнаяСтрока = Неопределено;

Пока Выборка.Следующий() Цикл

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

НайденнаяСтрока = Выборка.Ссылка;

Прервать;

КонецЕсли;

КонецЦикла;

Остановка при ошибке в данных

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

Оператор Продолжить: пропуск итерации вместо выхода

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

Пока Выборка.Следующий() Цикл

Если Выборка.ПометкаУдаления Тогда

Продолжить; // пропускаем помеченные на удаление

КонецЕсли;

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

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

КонецЕсли;

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

КонецЦикла;

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

Прерывание вложенных циклов

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

Способ 1: флаг выхода

Заведите булеву переменную, установите её перед «Прервать» во внутреннем цикле и проверьте во внешнем:

НужноПрервать = Ложь;

Пока ВыборкаПоДокументам.Следующий() Цикл

Пока ВыборкаПоСтрокам.Следующий() Цикл

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

НужноПрервать = Истина;

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

КонецЕсли;

КонецЦикла;

Если НужноПрервать Тогда

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

КонецЕсли;

КонецЦикла;

Способ 2: Возврат из процедуры

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

Сравнение вариантов выхода

Прервать

Завершает только текущий цикл. Подходит для одиночных циклов и поиска. Не выходит из вложенных уровней.

Флаг + Прервать

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

Возврат

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

Условие в заголовке Пока

Штатное завершение без операторов выхода. Самый читаемый вариант, если условие можно сформулировать заранее.

Защита от бесконечного цикла

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

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

МаксИтераций = 100000;

Итерация = 0;

Пока ЕстьДанныеДляОбработки() Цикл

Итерация = Итерация + 1;

Если Итерация > МаксИтераций Тогда

ЗаписьЖурналаРегистрации("ОбработкаДанных",

УровеньЖурналаРегистрации.Ошибка,,,

"Превышен лимит итераций цикла");

Прервать;

КонецЕсли;

// обработка порции данных

КонецЦикла;

Типичные ошибки
01
Вызов Продолжить до Выборка.Следующий() — счётчик выборки не сдвигается, цикл становится бесконечным
02
Ожидание, что Прервать выйдет из всех вложенных циклов — завершается только внутренний, внешний продолжает работать
03
Изменение коллекции (удаление строк таблицы значений) во время её обхода — пропускаются или повторно обрабатываются элементы
04
Прерывание цикла, записывающего данные, без транзакции — в базе остаются частично обновлённые объекты
05
Условие выхода проверяется только в конце тела цикла, хотя его можно было вынести в заголовок Пока — код читается хуже

Проверка результата и отладка

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

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

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

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

Срабатывание Прервать
Норма

В отладчике управление переходит на строку после КонецЦикла

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

Цикл продолжает выполняться — условие выхода не наступает

Количество итераций
Норма

Цикл завершается за ожидаемое число проходов

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

Счётчик растёт бесконечно — условие заголовка не меняется

Состояние данных после прерывания
Норма

Изменения либо зафиксированы полностью, либо откачены транзакцией

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

Часть объектов записана, часть нет — данные несогласованы

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

После Прервать во внутреннем цикле внешний тоже завершается (флаг или Возврат)

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

Внешний цикл продолжает перебор, хотя обработка должна была остановиться

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

Чем «Прервать» отличается от «Возврат» внутри цикла?

«Прервать» завершает только цикл — код после «КонецЦикла» продолжит выполняться. «Возврат» завершает всю процедуру или функцию целиком, включая любые циклы. Если после цикла есть обязательная логика (запись итогов, закрытие файлов), используйте «Прервать»; если нет — «Возврат» короче и нагляднее.

Работает ли «Прервать» в цикле «Для Каждого … Из … Цикл»?

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

Как выйти из цикла по нажатию кнопки пользователем?

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

Почему цикл «Пока» зависает, хотя внутри есть «Прервать»?

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

Можно ли прервать цикл из вызываемой процедуры?

Нет, оператор «Прервать» действует только в том методе, где написан. Чтобы вызванная процедура могла остановить цикл вызывающего кода, верните из неё булево значение (например, «Истина» — нужно прервать) и проверьте его после вызова, либо сгенерируйте исключение через ВызватьИсключение и обработайте его конструкцией «Попытка… Исключение» вокруг цикла.

Итог

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

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