Разработка и Конфигурация · 10 мин
Как остановить цикл в 1С: все способы прерывания
Как остановить цикл в 1С: операторы Прервать, Продолжить и Возврат, прерывание по условию, остановка зависшего кода в отладчике и типичные ошибки разработчиков.
Во встроенном языке 1С циклы Для, Для Каждого и Пока прерываются тремя операторами: Прервать полностью останавливает цикл, Продолжить пропускает текущую итерацию и переходит к следующей, а Возврат завершает всю процедуру или функцию вместе с циклом. Выбор зависит от того, нужно ли досрочно выйти из перебора, отфильтровать часть элементов или прекратить выполнение кода целиком.
Кроме штатных операторов есть и «аварийные» сценарии: код завис в бесконечном цикле, отладку нужно остановить вручную, а длительную обработку — прервать по требованию пользователя. Эти ситуации решаются иначе — через отладчик, настройки клиент-серверного режима и проверку условий выхода.
Ниже разобраны синтаксис и примеры каждого оператора, условия выбора между ними, способы остановить зависший цикл и типичные ошибки, которые приводят к бесконечным переборам и потере данных.
Оператор Прервать: полная остановка цикла
Оператор Прервать немедленно завершает выполнение ближайшего цикла, внутри которого он находится, и передаёт управление на первую строку после КонецЦикла. Это стандартный способ досрочного выхода, когда дальнейший перебор не имеет смысла — например, нужный элемент уже найден.
Типичный пример — поиск строки в таблице значений. Как только совпадение получено, перебирать остальные строки незачем: это экономит время, особенно на больших выборках.
Для Каждого Строка Из ТаблицаТоваров Цикл
Если Строка.Артикул = ИскомыйАртикул Тогда
НайденнаяСтрока = Строка;
Прервать;
КонецЕсли;
КонецЦикла;
Важно понимать, что Прервать останавливает только один уровень вложенности. Если цикл вложен в другой цикл, внешний продолжит работу. Чтобы выйти сразу из нескольких уровней, используют флаг-переменную или оператор Возврат.
// Выход из двух вложенных циклов через флаг
НужноПрервать = Ложь;
Для Каждого Заказ Из Заказы Цикл
Для Каждого Строка Из Заказ.Товары Цикл
Если Строка.Отменена Тогда
НужноПрервать = Истина;
Прервать;
КонецЕсли;
КонецЦикла;
Если НужноПрервать Тогда
Прервать;
КонецЕсли;
КонецЦикла;Оператор Продолжить: пропуск итерации без остановки цикла
Оператор Продолжить не останавливает цикл, а досрочно завершает текущую итерацию: всё, что написано после него внутри тела цикла, в этом проходе не выполняется, и перебор переходит к следующему элементу. Это удобно для фильтрации — когда часть элементов нужно просто пропустить.
Классический сценарий — обработка только подходящих строк. Вместо глубокой вложенности условий в начале итерации ставят проверку с Продолжить, и основной код остаётся «плоским» и читаемым.
Для Каждого Строка Из ТаблицаДокументов Цикл
Если Не Строка.Проведен Тогда
Продолжить; // непроведённые пропускаем
КонецЕсли;
// дальше обрабатываются только проведённые документы
КонецЦикла;
В цикле Пока с Продолжить нужна осторожность: если изменение счётчика стоит после этого оператора, итерация завершится до изменения переменной, и цикл может стать бесконечным. Счётчик в таких циклах безопаснее менять в самом начале тела.
Оператор Возврат: завершение процедуры вместе с циклом
Если после нахождения результата в процедуре или функции больше ничего не выполняется, проще использовать Возврат — он завершает всю процедуру, а значит, и цикл внутри неё на любом уровне вложенности. В функциях оператор пишется с возвращаемым значением: Возврат НайденноеЗначение;.
Функция НайтиКонтрагентаПоИНН(ИНН)
Для Каждого Контрагент Из СписокКонтрагентов Цикл
Если Контрагент.ИНН = ИНН Тогда
Возврат Контрагент.Ссылка;
КонецЕсли;
КонецЦикла;
Возврат Неопределено;
КонецФункции
Это самый чистый способ выйти из глубокой вложенности: не нужны флаги и повторные проверки во внешних циклах. Ограничение очевидно — после Возврат не выполнится никакой код процедуры, поэтому если после цикла есть обязательные завершающие действия (запись журнала, закрытие файла), их нужно вынести или выполнить до выхода.
Сравнение способов остановки
Досрочный выход из одного цикла, когда результат найден. Не подходит для выхода из нескольких вложенных циклов сразу.
Пропуск отдельных элементов при фильтрации. Не останавливает цикл; опасен в Пока, если счётчик меняется после него.
Выход из процедуры целиком, включая любые вложенные циклы. Не подходит, если после цикла нужен завершающий код.
Как прервать цикл по условию и по времени
Частый практический приём — ограничить цикл не только условием по данным, но и по времени выполнения или по числу итераций. Это защищает длительные обработки от зависания: например, обмен с внешним сервисом не должен крутиться дольше заданного лимита.
ВремяСтарта = ТекущаяДатаСеанса();
Пока Истина Цикл
// ... основная логика ...
Если ТекущаяДатаСеанса() - ВремяСтарта > 300 Тогда
Прервать; // не дольше 5 минут
КонецЕсли;
КонецЦикла;
Более корректная альтернатива — вынести условие в заголовок цикла Пока, тогда Прервать вообще не понадобится: Пока ЕстьДанные И ТекущаяДатаСеанса() - ВремяСтарта <= 300 Цикл. Такой код проще читать и сложнее сломать при доработке.
В управляемых формах длительные операции рекомендуется выносить в фоновые задания с длительными операциями БСП — там пользователь видит индикатор и может отменить выполнение штатной кнопкой, а не принудительным завершением сеанса.
Как остановить зависший цикл в отладчике и в рабочей базе
Если код завис в бесконечном цикле во время отладки, остановить его можно принудительно: в конфигураторе нажмите Ctrl+Break (команда «Остановить» в меню «Отладка») — выполнение прервётся на текущей строке, и вы увидите, где зациклился код. После этого завершите отладку кнопкой «Прекратить», исправьте условие выхода и запустите заново.
В файловой базе без отладки зависший сеанс останавливается закрытием приложения через диспетчер задач. Это допустимо для чтения данных, но рискованно, если шла запись: частично обработанные документы могут остаться в неконсистентном состоянии.
В клиент-серверном режиме фоновое задание или сеанс с зависшим циклом останавливается администратором через консоль кластера серверов 1С: найдите сеанс или фоновое задание и принудительно завершите его. Перед этим убедитесь, что задание действительно зависло, а не выполняет длительную, но корректную операцию — прерывание на середине записи оставит незавершённую транзакцию, которую СУБД откатит.
Типичные ошибки при остановке циклов
Самая частая причина бесконечных циклов — отсутствие изменения переменной условия. В цикле Пока НайденнаяСтрока <> Неопределено Цикл забывают получить следующую строку, и условие никогда не станет ложным. Перед запуском длительной обработки всегда проверяйте, что внутри тела цикла гарантированно меняется хотя бы одна переменная из условия.
Вторая распространённая ошибка — модификация коллекции во время перебора Для Каждого: удаление или добавление элементов в обходимую коллекцию приводит к пропуску элементов или ошибке. Если нужно удалять элементы, перебирайте коллекцию циклом Для с конца к началу или соберите элементы для удаления в отдельный массив и удалите после цикла.
Третья группа ошибок — неправильный выбор оператора: Прервать вместо Продолжить обрывает весь перебор на первом неподходящем элементе, а Продолжить вместо Прервать заставляет цикл молча обрабатывать лишние тысячи строк. Перед отправкой кода в работу прогоните его на маленьком тестовом наборе и проверьте число обработанных элементов.
Как проверить результат
Совпадает с ожидаемым количеством подходящих строк
Обработано меньше — возможен преждевременный Прервать
Цикл не выполняется ни разу, ошибок нет
Ошибка обращения к элементам или лишняя итерация
Завершается за предсказуемое время
Растёт непропорционально данным — признак лишних итераций
FAQ: частые вопросы об остановке циклов в 1С
Чем Прервать отличается от Продолжить?
Прервать полностью завершает цикл и передаёт управление коду после КонецЦикла. Продолжить завершает только текущую итерацию и запускает следующую. Первый нужен для выхода, второй — для фильтрации элементов.
Как выйти сразу из двух вложенных циклов?
Два рабочих способа: установить флаг во внутреннем цикле и проверить его во внешнем со вторым Прервать, либо обернуть логику в функцию и использовать Возврат — он завершит все уровни сразу.
Можно ли прервать цикл по нажатию кнопки пользователем?
Напрямую в синхронном коде — нет: пока выполняется цикл, интерфейс заблокирован. Решение — вынести операцию в фоновое задание (длительные операции БСП), где предусмотрена штатная отмена, либо выполнять обработку порциями через ПодключитьОбработчикОжидания.
Как остановить бесконечный цикл в запросе?
В языке запросов 1С циклов нет, поэтому зависание запроса — это не цикл, а тяжёлое соединение таблиц или отсутствие индексов. Такой запрос прерывается принудительным завершением сеанса в консоли кластера, а исправляется оптимизацией текста запроса и индексированием полей соединения.
Работает ли Прервать внутри попытки/исключения?
Да, оператор корректно работает внутри блока Попытка...Исключение...КонецПопытки: он прервёт цикл, а не передаст управление в обработчик исключения. Исключение срабатывает только на ошибки выполнения, а Прервать — штатная команда языка.
Что делать, если цикл зависает только на больших объёмах данных?
Скорее всего, это не бесконечный цикл, а квадратичная сложность: внутри перебора выполняется поиск по другой коллекции или запрос в цикле. Замените вложенный поиск на соответствие с заранее построенным индексом или перенесите выборку в один запрос с соединением.
Что важно запомнить
Прервать останавливает цикл, Продолжить пропускает итерацию, Возврат завершает всю процедуру с любым уровнем вложенности. Зависший цикл останавливается через Ctrl+Break в отладчике или консоль кластера. Главные причины бесконечных циклов — неизменяемое условие и счётчик после Продолжить.