Процедуры во встроенном языке 1С 8.3: объявление, вызов и отладка

· 9 мин

Содержание

Чтобы выполнить процедуру в 1С, её объявляют блоком Процедура Имя() … КонецПроцедуры в нужном модуле, а затем вызывают по имени: Имя();. Если процедура лежит в другом модуле, у неё должно стоять ключевое слово Экспорт, а вызов пишется через имя модуля: ОбщийМодуль.Имя();.

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

Процедура в 1С: что это и чем она отличается от функции

Процедура — именованный блок кода, который выполняет действие и ничего не возвращает. Функция делает то же самое, но обязана вернуть значение через Возврат Значение;.

ПроцедураФункция
ОбъявлениеПроцедура … КонецПроцедурыФункция … КонецФункции
Возвращает значениенетда, через Возврат
Можно ли вызвать в выражениинетда: Сумма = Посчитать();
Возврат без значенияда, для досрочного выходанет
Типичное применениезаполнить, записать, показатьвычислить, найти, проверить

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

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

Где разместить процедуру: модуль и контекст исполнения

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

Какой модуль выбрать

  • 📄 Модуль формы — код, связанный с одной формой: команды, обработчики полей, заполнение реквизитов формы.
  • 📦 Модуль объекта — логика конкретного документа или справочника: проведение, проверки при записи, заполнение по основанию.
  • 🗂 Модуль менеджера — действия «над всеми объектами» вида: печать, выборки, служебные функции без конкретного экземпляра.
  • 🔧 Общий модуль — процедуры, которые нужны из многих мест конфигурации. В свойствах модуля ставят флажки: Сервер, Клиент (управляемое приложение), Вызов сервера, Глобальный, Привилегированный.

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

Директивы компиляции в модуле формы

В модуле управляемой формы над каждой процедурой ставят директиву. Она говорит, на какой стороне выполняется код.

ДирективаГде выполняетсяДоступ к данным формыКогда использовать
&НаКлиентеклиентдадиалоги, реакция на действия пользователя
&НаСервересерверда, форма передаётся на серверработа с базой и реквизитами формы
&НаСервереБезКонтекстасервернетзапросы, где форма не нужна
&НаКлиентеНаСервереБезКонтекстаобе сторонынетчистые вычисления без базы

&НаСервереБезКонтекста работает быстрее &НаСервере: платформа не гоняет данные формы туда и обратно. Если процедуре форма не нужна, выбирайте её.

Как написать процедуру: синтаксис с параметрами

Минимальная процедура

Процедура ПоказатьПриветствие()
    Сообщить("Процедура выполнена");
КонецПроцедуры

Имя пишется без пробелов, кириллицей или латиницей, первым символом не может быть цифра. Точка с запятой после КонецПроцедуры не нужна.

Параметры, значения по умолчанию и Знач

Процедура ЗаписатьВЖурнал(ТекстСообщения, Уровень = "Информация", Знач Попытка = 1) Экспорт
    Если ПустаяСтрока(ТекстСообщения) Тогда
        Возврат;
    КонецЕсли;
    Сообщить(СтрШаблон("[%1] %2 (попытка %3)", Уровень, ТекстСообщения, Формат(Попытка, "ЧГ=0")));
КонецПроцедуры

Что здесь происходит:

  1. ТекстСообщения — обязательный параметр. Без него вызов не скомпилируется.
  2. Уровень = "Информация" — необязательный. При вызове ЗаписатьВЖурнал("Готово"); он примет значение по умолчанию.
  3. Знач — параметр передаётся по значению. Без Знач параметр передаётся по ссылке: если процедура изменит его, изменится и переменная вызывающего кода.
  4. Возврат; — досрочный выход. Код ниже не выполнится.
  5. Экспорт — процедуру можно вызвать из другого модуля.

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

Локальные переменные

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

Порядок процедур в модуле в 8.3 значения не имеет: процедуру можно вызвать выше по тексту, чем она объявлена.

Как выполнить процедуру: способы вызова

Способ 1. Вызов в том же модуле

Достаточно имени и скобок:

ЗаписатьВЖурнал("Документ проведён", "Ошибка");

Скобки ставятся даже без параметров: ПоказатьПриветствие();.

Способ 2. Вызов процедуры общего модуля

  1. Откройте общий модуль и убедитесь, что у процедуры есть Экспорт.
  2. Проверьте флажки модуля: для вызова с сервера нужен Сервер, с клиента — Клиент (управляемое приложение).
  3. Вызывайте через имя модуля: ЖурналСервер.ЗаписатьВЖурнал("Готово");.

Если у модуля стоит флажок Глобальный, имя модуля писать не обязательно. Злоупотреблять глобальными модулями не стоит: они компилируются при старте сеанса и замедляют запуск.

Способ 3. С клиента на сервер

Клиентская процедура не видит базу. Чтобы выполнить серверный код из команды формы, делают пару процедур:

&НаКлиенте
Процедура Пересчитать(Команда)
    ПересчитатьНаСервере();
КонецПроцедуры

&НаСервере
Процедура ПересчитатьНаСервере()
    // работа с базой и реквизитами формы
КонецПроцедуры

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

Способ 4. Через обработку оповещения

Немодальные диалоги (ПоказатьВопрос, ПоказатьВводЧисла) не ждут ответа. Результат передают в процедуру, имя которой указывают в ОписаниеОповещения. Эта процедура должна быть экспортной.

Способ 5. Асинхронно через Асинх и Ждать

Начиная с платформы 8.3.18 клиентскую процедуру можно объявить как Асинх Процедура … и ждать ответа диалога оператором Ждать. Код читается сверху вниз, без отдельной процедуры-обработчика.

Способ 6. Фоновое задание и регламентное задание

Долгую серверную процедуру запускают в фоне: ФоновыеЗадания.Выполнить("ИмяМодуля.ИмяПроцедуры", Параметры). Процедура должна быть экспортной и лежать в серверном неглобальном общем модуле.

Регламентное задание вызывает процедуру общего модуля по расписанию. В типовых конфигурациях на БСП запустить его вручную можно в Администрирование → Обслуживание → Регламентные и фоновые задания.

Способ 7. Динамический вызов по имени

Оператор Выполнить("ЖурналСервер.ЗаписатьВЖурнал(""Тест"")"); выполняет строку кода. Он работает только на сервере и в толстом клиенте.

Не подставляйте в Выполнить строку, которую ввёл пользователь: это прямой путь к выполнению произвольного кода. В конфигурациях на БСП для такого вызова есть ОбщегоНазначения.ВыполнитьМетодКонфигурации, который проверяет имя метода.

Сравнение способов

СпособКогдаРиски
Прямой вызовтот же модульпочти нет
Общий модулькод нужен во многих местахзабытый Экспорт или флажок
Клиент → серверкоманда формы работает с базойлишние серверные вызовы тормозят форму
Оповещение / Асинхждём ответ пользователяпроцедура-обработчик без Экспорт
Фоновое заданиедолгие операцииошибки не видны пользователю сразу
Выполнитьимя известно только в момент работыбезопасность, сложная отладка

Отладка процедуры в конфигураторе

Когда процедура выполняется, но делает не то, нужен отладчик. Он встроен в конфигуратор.

Пошаговый запуск под отладкой

  1. Откройте модуль и встаньте на строку внутри процедуры.
  2. Нажмите F9 — слева появится красная точка останова.
  3. Запустите режим Отладка → Начать отладку → 1С:Предприятие (или F5).
  4. В пользовательском режиме выполните действие, которое вызывает процедуру.
  5. Конфигуратор остановится на строке с точкой и подсветит её.

Дальше управляете выполнением клавишами:

КлавишаДействие
F11шагнуть в вызываемую процедуру
F10выполнить строку, не заходя внутрь вызова
Shift+F11выйти из текущей процедуры
F5продолжить до следующей точки останова
Shift+F9вычислить выражение в текущий момент

Приёмы, которые экономят время

  • 🔍 Табло. Перетащите в него переменные — их значения обновляются на каждом шаге.
  • 🎯 Условная точка останова. В контекстном меню точки задайте условие, например НомерСтроки = 150. Отладчик не будет останавливаться на каждой итерации цикла.
  • 🧯 Остановка по ошибке. В меню Отладка включите остановку по ошибке: отладчик встанет ровно на той строке, где возникло исключение, даже внутри Попытка … Исключение.
  • 🧵 Стек вызовов. Показывает цепочку, по которой выполнение пришло в процедуру. Помогает, когда процедуру вызывают из нескольких мест.

Чтобы отлаживать серверный код клиент-серверной базы, на сервере 1С должна быть включена отладка. Обычно сервер запускают с ключом -debug, а в конфигураторе выбирают отладку по протоколу HTTP. Перезапуск службы сервера оборвёт сеансы всех пользователей — делайте это вне рабочего времени.

Выполнить процедуру без конфигуратора

Иногда кусок кода нужно один раз выполнить в рабочей базе. Для этого пишут внешнюю обработку (.epf) с командой, которая вызывает нужную процедуру, и открывают её через меню Файл → Открыть. Для открытия внешних обработок у пользователя должно быть соответствующее право.

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

Примеры процедур для рабочих задач

Заполнить табличную часть из запроса

&НаКлиенте
Процедура ЗаполнитьТовары(Команда)
    ЗаполнитьТоварыНаСервере();
КонецПроцедуры

&НаСервере
Процедура ЗаполнитьТоварыНаСервере()
    Запрос = Новый Запрос;
    Запрос.Текст =
    "ВЫБРАТЬ ПЕРВЫЕ 10
    |    Номенклатура.Ссылка КАК Номенклатура
    |ИЗ
    |    Справочник.Номенклатура КАК Номенклатура
    |ГДЕ
    |    НЕ Номенклатура.ЭтоГруппа
    |    И НЕ Номенклатура.ПометкаУдаления";
    Выборка = Запрос.Выполнить().Выбрать();
    Объект.Товары.Очистить();
    Пока Выборка.Следующий() Цикл
        НоваяСтрока = Объект.Товары.Добавить();
        НоваяСтрока.Номенклатура = Выборка.Номенклатура;
    КонецЦикла;
КонецПроцедуры

Пример рассчитан на документ с табличной частью Товары и иерархический справочник Номенклатура с группами. Если групп в справочнике нет, условие ЭтоГруппа уберите.

Спросить пользователя и выполнить действие

&НаКлиенте
Процедура ОчиститьТовары(Команда)
    Оповещение = Новый ОписаниеОповещения("ОчиститьТоварыЗавершение", ЭтотОбъект);
    ПоказатьВопрос(Оповещение, "Очистить табличную часть?", РежимДиалогаВопрос.ДаНет);
КонецПроцедуры

&НаКлиенте
Процедура ОчиститьТоварыЗавершение(Ответ, ДополнительныеПараметры) Экспорт
    Если Ответ = КодВозвратаДиалога.Да Тогда
        Объект.Товары.Очистить();
    КонецЕсли;
КонецПроцедуры

Тот же сценарий на Асинх (платформа 8.3.18 и выше):

&НаКлиенте
Асинх Процедура ОчиститьТоварыАсинх(Команда)
    Ответ = Ждать ВопросАсинх("Очистить табличную часть?", РежимДиалогаВопрос.ДаНет);
    Если Ответ = КодВозвратаДиалога.Да Тогда
        Объект.Товары.Очистить();
    КонецЕсли;
КонецПроцедуры

Запустить долгую обработку в фоне

// Общий модуль ОбработкаДанныхСервер: флажок «Сервер», не глобальный
Процедура ПересчитатьДанные(Организация) Экспорт
    // длительная серверная логика
КонецПроцедуры

// Модуль формы
&НаСервереБезКонтекста
Процедура ЗапуститьПересчетНаСервере(Организация)
    Параметры = Новый Массив;
    Параметры.Добавить(Организация);
    ФоновыеЗадания.Выполнить("ОбработкаДанныхСервер.ПересчитатьДанные", Параметры, , "Пересчёт данных");
КонецПроцедуры

Пользователь сразу получает управление формой, а пересчёт идёт на сервере. Ход выполнения виден в списке фоновых заданий.

Ошибки при вызове процедур и что они значат

Сообщения платформы обычно прямо указывают на причину. Выберите своё:

Диагностика: выберите симптом

Быстрая проверка до запуска: F7 в открытом модуле проверяет его синтаксис, а Конфигурация → Проверка конфигурации находит ошибки во всех модулях сразу, без открытия пользовательского режима.

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

Можно ли вызвать процедуру формы из общего модуля?
Напрямую — нет. Общий модуль не знает о конкретной форме. Передайте в процедуру общего модуля нужные данные параметрами или используйте оповещение формы.
Сколько параметров может быть у процедуры?
Жёсткого практического предела нет, но больше 5–7 параметров читать тяжело. Удобнее передать одну Структура с именованными полями.
Чем `Экспорт` в модуле объекта отличается от `Экспорт` в общем модуле?
В модуле объекта экспортную процедуру вызывают через экземпляр: ДокументОбъект.Пересчитать();. В общем модуле — через имя модуля, без создания объекта.
Почему процедура выполняется дважды?
Чаще всего её вызывают и из обработчика события, и явно в коде, либо обработчик назначен двум элементам формы. Поставьте точку останова и посмотрите стек вызовов при каждой остановке.
Можно ли выполнить процедуру по таймеру?
Да. На клиенте это ПодключитьОбработчикОжидания("ИмяПроцедуры", 60), процедура должна быть в модуле формы или глобальном клиентском модуле. На сервере для расписания используют регламентное задание.