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

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

Как правильно закончить цикл в 1С

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

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

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

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

Какие циклы есть в 1С и как они завершаются сами

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

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

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

Оператор «Прервать» — полный выход из цикла

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

Типичный пример поиска товара в таблице значений:

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

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

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

НайденнаяСтрока = СтрокаТовара;

Прервать;

КонецЕсли;

КонецЦикла;

Если НайденнаяСтрока = Неопределено Тогда

Сообщить("Товар не найден");

КонецЕсли;

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

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

Как организовать выход из цикла при поиске
  1. 1
    Объявите переменную-результат до цикла и присвойте ей Неопределено
  2. 2
    Внутри цикла проверьте условие поиска через Если
  3. 3
    При выполнении условия сохраните найденный элемент в переменную
  4. 4
    Вызовите Прервать, чтобы завершить перебор
  5. 5
    После цикла проверьте переменную: Неопределено означает, что элемент не найден

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

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

Пример обработки только проведённых документов из выборки:

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

Если Не Выборка.Проведен Тогда

Продолжить;

КонецЕсли;

// обработка только проведённых документов

КонецЦикла;

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

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

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

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

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

Для Каждого СтрокаТЧ Из ТабличнаяЧасть Цикл

Для Каждого Элемент Из СтрокаТЧ.СписокСерий Цикл

Если Элемент.Просрочен Тогда

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

Прервать;

КонецЕсли;

КонецЦикла;

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

Прервать;

КонецЕсли;

КонецЦикла;

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

Способы выйти из вложенных циклов

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

Подходит, когда код нельзя вынести в отдельную функцию. Минус — лишняя переменная и проверка в каждом уровне вложенности.

Возврат из функции

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

Прервать только внутренний цикл

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

Выход из цикла по выборке запроса

При обходе результата запроса цикл строится на методе Следующий(): Пока Выборка.Следующий() Цикл. Здесь Прервать работает так же, как в любом другом цикле, но есть нюансы, связанные с ресурсами.

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

Конструкция ВЫБРАТЬ ПЕРВЫЕ N в тексте запроса решает задачу «получить несколько записей и закончить» эффективнее любого Прервать: сервер вернёт ровно столько строк, сколько требуется, и перебор завершится естественным образом.

Бесконечный цикл и как его остановить

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

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

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

Типичные ошибки при завершении цикла

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

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

Типичные ошибки
01
Продолжить вместо Прервать — цикл перебирает всю коллекцию, обработка работает медленно
02
Прервать вместо Продолжить — обрабатывается только часть данных, ошибка всплывает поздно
03
Прервать до сохранения результата в переменную — найденное значение теряется
04
Ожидание выхода из всех вложенных циклов одним Прервать — внешний цикл продолжает работу
05
Изменение счётчика после Продолжить — счётчик не меняется, цикл становится бесконечным

Проверка результата после выхода из цикла

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

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

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

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

Переменная-результат после цикла
Норма

Содержит найденный элемент или явное значение по умолчанию

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

Неопределено там, где элемент должен был найтись — проверьте условие и место Прервать

Количество обработанных элементов
Норма

Совпадает с ожидаемым объёмом данных

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

Обработано меньше — где-то сработал Прервать или лишний Продолжить

Время выполнения обработки
Норма

Завершается сразу после нахождения результата

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

Растёт пропорционально размеру коллекции — Прервать не срабатывает

Итог

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

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

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

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

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

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

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

Можно ли прервать цикл Для Каждого по условию?

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

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

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

Есть ли в 1С аналог оператора goto или меток для выхода из цикла?

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

Что быстрее: цикл с Прервать или метод Найти у таблицы значений?

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