Процедуры во встроенном языке 1С 8.3: объявление, вызов и отладка
Содержание
Чтобы выполнить процедуру в 1С, её объявляют блоком Процедура Имя() … КонецПроцедуры в нужном модуле, а затем вызывают по имени: Имя();. Если процедура лежит в другом модуле, у неё должно стоять ключевое слово Экспорт, а вызов пишется через имя модуля: ОбщийМодуль.Имя();.
На практике код чаще всего «не выполняется» не из-за синтаксиса, а из-за контекста: процедура объявлена на сервере, а вызывают её с клиента, или она не экспортирована. Ниже по шагам: где разместить процедуру, как её написать, какими способами запустить, как пройти отладчиком и что значат типовые сообщения об ошибках. Всё относится к платформе 8.3 и управляемым формам.
Процедура в 1С: что это и чем она отличается от функции
Процедура — именованный блок кода, который выполняет действие и ничего не возвращает. Функция делает то же самое, но обязана вернуть значение через Возврат Значение;.
| Процедура | Функция | |
|---|---|---|
| Объявление | Процедура … КонецПроцедуры | Функция … КонецФункции |
| Возвращает значение | нет | да, через Возврат |
| Можно ли вызвать в выражении | нет | да: Сумма = Посчитать(); |
Возврат без значения | да, для досрочного выхода | нет |
| Типичное применение | заполнить, записать, показать | вычислить, найти, проверить |
Процедуры нужны, чтобы не копировать один и тот же код по десятку мест. Заполнение табличной части, проверка реквизитов перед записью, отправка уведомления — всё это пишут один раз и вызывают по имени.
Ещё одна группа — обработчики событий. Например, ПриОткрытии, ПередЗаписью, ОбработкаПроведения. Это тоже процедуры, только их вызывает сама платформа в нужный момент. Вы не пишете вызов вручную, вы пишете тело.
Где разместить процедуру: модуль и контекст исполнения
Первое решение до написания кода — в каком модуле будет жить процедура. От этого зависит, кто сможет её вызвать.
Какой модуль выбрать
- 📄 Модуль формы — код, связанный с одной формой: команды, обработчики полей, заполнение реквизитов формы.
- 📦 Модуль объекта — логика конкретного документа или справочника: проведение, проверки при записи, заполнение по основанию.
- 🗂 Модуль менеджера — действия «над всеми объектами» вида: печать, выборки, служебные функции без конкретного экземпляра.
- 🔧 Общий модуль — процедуры, которые нужны из многих мест конфигурации. В свойствах модуля ставят флажки:
Сервер,Клиент (управляемое приложение),Вызов сервера,Глобальный,Привилегированный.
Для общих модулей удобно следовать соглашению по именам: суффикс Сервер, Клиент, ВызовСервера, КлиентСервер. По имени сразу понятно, где выполняется код, и меньше путаницы при вызове.
Директивы компиляции в модуле формы
В модуле управляемой формы над каждой процедурой ставят директиву. Она говорит, на какой стороне выполняется код.
| Директива | Где выполняется | Доступ к данным формы | Когда использовать |
|---|---|---|---|
&НаКлиенте | клиент | да | диалоги, реакция на действия пользователя |
&НаСервере | сервер | да, форма передаётся на сервер | работа с базой и реквизитами формы |
&НаСервереБезКонтекста | сервер | нет | запросы, где форма не нужна |
&НаКлиентеНаСервереБезКонтекста | обе стороны | нет | чистые вычисления без базы |
&НаСервереБезКонтекста работает быстрее &НаСервере: платформа не гоняет данные формы туда и обратно. Если процедуре форма не нужна, выбирайте её.
Как написать процедуру: синтаксис с параметрами
Минимальная процедура
Процедура ПоказатьПриветствие()
Сообщить("Процедура выполнена");
КонецПроцедуры
Имя пишется без пробелов, кириллицей или латиницей, первым символом не может быть цифра. Точка с запятой после КонецПроцедуры не нужна.
Параметры, значения по умолчанию и Знач
Процедура ЗаписатьВЖурнал(ТекстСообщения, Уровень = "Информация", Знач Попытка = 1) Экспорт
Если ПустаяСтрока(ТекстСообщения) Тогда
Возврат;
КонецЕсли;
Сообщить(СтрШаблон("[%1] %2 (попытка %3)", Уровень, ТекстСообщения, Формат(Попытка, "ЧГ=0")));
КонецПроцедуры
Что здесь происходит:
ТекстСообщения— обязательный параметр. Без него вызов не скомпилируется.Уровень = "Информация"— необязательный. При вызовеЗаписатьВЖурнал("Готово");он примет значение по умолчанию.Знач— параметр передаётся по значению. БезЗначпараметр передаётся по ссылке: если процедура изменит его, изменится и переменная вызывающего кода.Возврат;— досрочный выход. Код ниже не выполнится.Экспорт— процедуру можно вызвать из другого модуля.
Передача по ссылке — частый источник «необъяснимых» багов. Если процедура меняет параметр как локальную переменную, ставьте Знач. Для таблиц значений и массивов Знач не создаёт копию коллекции: изменение строк всё равно будет видно снаружи. Нужна копия — делайте её явно, например Таблица.Скопировать().
Локальные переменные
Переменные внутри процедуры объявляют через Перем в начале тела или создают присваиванием. Они живут только до КонецПроцедуры. Переменные модуля объявляются в его начале, до всех процедур.
Порядок процедур в модуле в 8.3 значения не имеет: процедуру можно вызвать выше по тексту, чем она объявлена.
Как выполнить процедуру: способы вызова
Способ 1. Вызов в том же модуле
Достаточно имени и скобок:
ЗаписатьВЖурнал("Документ проведён", "Ошибка");
Скобки ставятся даже без параметров: ПоказатьПриветствие();.
Способ 2. Вызов процедуры общего модуля
- Откройте общий модуль и убедитесь, что у процедуры есть
Экспорт. - Проверьте флажки модуля: для вызова с сервера нужен
Сервер, с клиента —Клиент (управляемое приложение). - Вызывайте через имя модуля:
ЖурналСервер.ЗаписатьВЖурнал("Готово");.
Если у модуля стоит флажок Глобальный, имя модуля писать не обязательно. Злоупотреблять глобальными модулями не стоит: они компилируются при старте сеанса и замедляют запуск.
Способ 3. С клиента на сервер
Клиентская процедура не видит базу. Чтобы выполнить серверный код из команды формы, делают пару процедур:
&НаКлиенте
Процедура Пересчитать(Команда)
ПересчитатьНаСервере();
КонецПроцедуры
&НаСервере
Процедура ПересчитатьНаСервере()
// работа с базой и реквизитами формы
КонецПроцедуры
Из клиентского кода в общий серверный модуль можно попасть, только если у модуля стоит Вызов сервера. Передавать с клиента на сервер можно примитивы, ссылки, массивы и структуры. Объекты вида ДокументОбъект через границу клиент-сервер не передаются.
Способ 4. Через обработку оповещения
Немодальные диалоги (ПоказатьВопрос, ПоказатьВводЧисла) не ждут ответа. Результат передают в процедуру, имя которой указывают в ОписаниеОповещения. Эта процедура должна быть экспортной.
Способ 5. Асинхронно через Асинх и Ждать
Начиная с платформы 8.3.18 клиентскую процедуру можно объявить как Асинх Процедура … и ждать ответа диалога оператором Ждать. Код читается сверху вниз, без отдельной процедуры-обработчика.
Способ 6. Фоновое задание и регламентное задание
Долгую серверную процедуру запускают в фоне: ФоновыеЗадания.Выполнить("ИмяМодуля.ИмяПроцедуры", Параметры). Процедура должна быть экспортной и лежать в серверном неглобальном общем модуле.
Регламентное задание вызывает процедуру общего модуля по расписанию. В типовых конфигурациях на БСП запустить его вручную можно в Администрирование → Обслуживание → Регламентные и фоновые задания.
Способ 7. Динамический вызов по имени
Оператор Выполнить("ЖурналСервер.ЗаписатьВЖурнал(""Тест"")"); выполняет строку кода. Он работает только на сервере и в толстом клиенте.
Не подставляйте в Выполнить строку, которую ввёл пользователь: это прямой путь к выполнению произвольного кода. В конфигурациях на БСП для такого вызова есть ОбщегоНазначения.ВыполнитьМетодКонфигурации, который проверяет имя метода.
Сравнение способов
| Способ | Когда | Риски |
|---|---|---|
| Прямой вызов | тот же модуль | почти нет |
| Общий модуль | код нужен во многих местах | забытый Экспорт или флажок |
| Клиент → сервер | команда формы работает с базой | лишние серверные вызовы тормозят форму |
Оповещение / Асинх | ждём ответ пользователя | процедура-обработчик без Экспорт |
| Фоновое задание | долгие операции | ошибки не видны пользователю сразу |
Выполнить | имя известно только в момент работы | безопасность, сложная отладка |
Отладка процедуры в конфигураторе
Когда процедура выполняется, но делает не то, нужен отладчик. Он встроен в конфигуратор.
Пошаговый запуск под отладкой
- Откройте модуль и встаньте на строку внутри процедуры.
- Нажмите
F9— слева появится красная точка останова. - Запустите режим
Отладка → Начать отладку → 1С:Предприятие(илиF5). - В пользовательском режиме выполните действие, которое вызывает процедуру.
- Конфигуратор остановится на строке с точкой и подсветит её.
Дальше управляете выполнением клавишами:
| Клавиша | Действие |
|---|---|
F11 | шагнуть в вызываемую процедуру |
F10 | выполнить строку, не заходя внутрь вызова |
Shift+F11 | выйти из текущей процедуры |
F5 | продолжить до следующей точки останова |
Shift+F9 | вычислить выражение в текущий момент |
Приёмы, которые экономят время
- 🔍 Табло. Перетащите в него переменные — их значения обновляются на каждом шаге.
- 🎯 Условная точка останова. В контекстном меню точки задайте условие, например
НомерСтроки = 150. Отладчик не будет останавливаться на каждой итерации цикла. - 🧯 Остановка по ошибке. В меню
Отладкавключите остановку по ошибке: отладчик встанет ровно на той строке, где возникло исключение, даже внутриПопытка … Исключение. - 🧵 Стек вызовов. Показывает цепочку, по которой выполнение пришло в процедуру. Помогает, когда процедуру вызывают из нескольких мест.
Чтобы отлаживать серверный код клиент-серверной базы, на сервере 1С должна быть включена отладка. Обычно сервер запускают с ключом -debug, а в конфигураторе выбирают отладку по протоколу HTTP. Перезапуск службы сервера оборвёт сеансы всех пользователей — делайте это вне рабочего времени.
Выполнить процедуру без конфигуратора
Иногда кусок кода нужно один раз выполнить в рабочей базе. Для этого пишут внешнюю обработку
(.epf) с командой, которая вызывает нужную процедуру, и открывают её через меню Файл → Открыть. Для открытия внешних обработок у пользователя должно быть соответствующее право.
Перед выполнением кода, который меняет данные, сделайте резервную копию базы : откатить массовую запись без копии нельзя.
Примеры процедур для рабочих задач
Заполнить табличную часть из запроса
&НаКлиенте
Процедура ЗаполнитьТовары(Команда)
ЗаполнитьТоварыНаСервере();
КонецПроцедуры
&НаСервере
Процедура ЗаполнитьТоварыНаСервере()
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 10
| Номенклатура.Ссылка КАК Номенклатура
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| НЕ Номенклатура.ЭтоГруппа
| И НЕ Номенклатура.ПометкаУдаления";
Выборка = Запрос.Выполнить().Выбрать();
Объект.Товары.Очистить();
Пока Выборка.Следующий() Цикл
НоваяСтрока = Объект.Товары.Добавить();
НоваяСтрока.Номенклатура = Выборка.Номенклатура;
КонецЦикла;
КонецПроцедуры
Пример рассчитан на документ с табличной частью Товары и иерархический справочник Номенклатура с группами. Если групп в справочнике нет, условие ЭтоГруппа уберите.
Спросить пользователя и выполнить действие
&НаКлиенте
Процедура ОчиститьТовары(Команда)
Оповещение = Новый ОписаниеОповещения("ОчиститьТоварыЗавершение", ЭтотОбъект);
ПоказатьВопрос(Оповещение, "Очистить табличную часть?", РежимДиалогаВопрос.ДаНет);
КонецПроцедуры
&НаКлиенте
Процедура ОчиститьТоварыЗавершение(Ответ, ДополнительныеПараметры) Экспорт
Если Ответ = КодВозвратаДиалога.Да Тогда
Объект.Товары.Очистить();
КонецЕсли;
КонецПроцедуры
Тот же сценарий на Асинх (платформа 8.3.18 и выше):
&НаКлиенте
Асинх Процедура ОчиститьТоварыАсинх(Команда)
Ответ = Ждать ВопросАсинх("Очистить табличную часть?", РежимДиалогаВопрос.ДаНет);
Если Ответ = КодВозвратаДиалога.Да Тогда
Объект.Товары.Очистить();
КонецЕсли;
КонецПроцедуры
Запустить долгую обработку в фоне
// Общий модуль ОбработкаДанныхСервер: флажок «Сервер», не глобальный
Процедура ПересчитатьДанные(Организация) Экспорт
// длительная серверная логика
КонецПроцедуры
// Модуль формы
&НаСервереБезКонтекста
Процедура ЗапуститьПересчетНаСервере(Организация)
Параметры = Новый Массив;
Параметры.Добавить(Организация);
ФоновыеЗадания.Выполнить("ОбработкаДанныхСервер.ПересчитатьДанные", Параметры, , "Пересчёт данных");
КонецПроцедуры
Пользователь сразу получает управление формой, а пересчёт идёт на сервере. Ход выполнения виден в списке фоновых заданий.
Ошибки при вызове процедур и что они значат
Сообщения платформы обычно прямо указывают на причину. Выберите своё:
Экспорт, в имени опечатка или вызов идёт не из того контекста: клиентский код вызывает процедуру с директивой &НаСервере из общего модуля без флажка Вызов сервера.Итог = Пересчитать();. Либо уберите присваивание, либо переделайте процедуру в функцию с Возврат.ОписаниеОповещения, не помечена Экспорт или её имя в строке набрано с ошибкой.Быстрая проверка до запуска: F7 в открытом модуле проверяет его синтаксис, а Конфигурация → Проверка конфигурации находит ошибки во всех модулях сразу, без открытия пользовательского режима.
Частые вопросы
Можно ли вызвать процедуру формы из общего модуля?
Сколько параметров может быть у процедуры?
Структура с именованными полями.Чем `Экспорт` в модуле объекта отличается от `Экспорт` в общем модуле?
ДокументОбъект.Пересчитать();. В общем модуле — через имя модуля, без создания объекта.Почему процедура выполняется дважды?
Можно ли выполнить процедуру по таймеру?
ПодключитьОбработчикОжидания("ИмяПроцедуры", 60), процедура должна быть в модуле формы или глобальном клиентском модуле. На сервере для расписания используют регламентное задание.