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