Процедуры во встроенном языке 1С: от объявления до вызова с сервера
Содержание
Чтобы создать процедуру в 1С 8.3, откройте нужный модуль в Конфигураторе и напишите блок Процедура Имя(Параметры) … КонецПроцедуры. Если процедуру будут вызывать из других модулей, добавьте после скобок слово Экспорт. В модуле формы перед объявлением поставьте директиву компиляции, например &НаСервере.
Типичная ситуация: разработчику поручили доработать печатную форму или кнопку на форме документа. Код в обработчике разрастается до 200 строк, и его пора разбить на процедуры. Ниже — как это сделать правильно, чтобы код работал на нужной стороне и не тормозил.
Синтаксис объявления процедуры в 1С
Процедура — именованный блок кода, который выполняет действие и не возвращает значение. Минимальное объявление выглядит так:
Процедура ЗаполнитьКомментарий()
Комментарий = "Заполнено автоматически";
КонецПроцедуры
Полный формат объявления:
&НаСервере
Процедура ПересчитатьСуммы(Знач СтавкаНДС, ТаблицаТоваров, ОкруглятьДоРубля = Ложь) Экспорт
// тело процедуры
КонецПроцедуры
Из чего состоит строка объявления:
- 🏷️
&НаСервере— директива компиляции. Нужна в модулях форм и в модулях команд. - 🔤
ПересчитатьСуммы— имя. Буквы, цифры и подчёркивание, начинается не с цифры. - 📥
(Знач СтавкаНДС, …)— список параметров через запятую. Скобки обязательны, даже если параметров нет. - 📤
Экспорт— делает процедуру доступной из других модулей. - 🔚
КонецПроцедуры— закрывает блок. Точка с запятой после него не нужна.
Правила именования
Стандарты разработки 1С рекомендуют имена в стиле «ГлаголСуществительное» без пробелов, каждое слово с заглавной: ЗаполнитьТабличнуюЧасть, ПроверитьЗаполнениеРеквизитов. Имя должно отвечать на вопрос «что делает процедура». Имена Процедура1 или Обработка через месяц не поймёт никто, включая автора.
Перед Процедура удобно писать комментарий с описанием параметров. Конфигуратор и EDT показывают его во всплывающей подсказке при вызове.
// Пересчитывает суммы в табличной части с учётом ставки НДС.
//
// Параметры:
// СтавкаНДС - Число - ставка в процентах, например 20.
// ТаблицаТоваров - ТаблицаЗначений - строки с колонками Цена, Количество, Сумма.
// ОкруглятьДоРубля - Булево - округлять ли итог до целых рублей.
//
Процедура ПересчитатьСуммы(Знач СтавкаНДС, ТаблицаТоваров, ОкруглятьДоРубля = Ложь) Экспорт
Порядок в модуле
Модуль 1С состоит из трёх частей, и порядок жёсткий:
- Раздел объявления переменных (
Перем). - Раздел процедур и функций.
- Раздел основной программы — операторы вне процедур.
Внутри второго раздела процедуры можно располагать в любом порядке. Вызвать процедуру, объявленную ниже по тексту, можно без предварительного объявления.
Где разместить процедуру: модули и директивы компиляции
Самый частый вопрос новичка — «в какой модуль писать». От этого зависит, кто сможет вызвать процедуру и на какой стороне она выполнится.
| Модуль | Что туда класть | Директивы |
|---|---|---|
| Модуль формы | Обработчики событий формы и элементов, логика интерфейса | Обязательны: &НаКлиенте, &НаСервере и др. |
| Модуль объекта | Логика конкретного документа или элемента: ПередЗаписью, ОбработкаПроведения | Не нужны, код серверный |
| Модуль менеджера | Действия с объектами этого вида в целом: печать, выборки, заполнение по умолчанию | Не нужны |
| Общий модуль | Код, который нужен в разных местах конфигурации | Задаются флажками в свойствах модуля |
| Модуль команды | Обработчик ОбработкаКоманды | &НаКлиенте |
Директивы в модуле формы
Форма живёт сразу на двух сторонах: клиентской и серверной. Директива говорит платформе, где компилировать процедуру.
- 🖥️
&НаКлиенте— работа с элементами формы, диалоги, вопросы пользователю. - 🗄️
&НаСервере— запросы к базе, доступ к реквизитам формы и объекту на сервере. - ⚡
&НаСервереБезКонтекста— серверный код без передачи данных формы. Быстрее обычного серверного вызова. - 🔁
&НаКлиентеНаСервереБезКонтекста— код, который компилируется на обеих сторонах. Подходит для расчётов без обращения к базе.
Если директиву не указать, процедура в модуле формы считается &НаКлиенте.
Флажки общего модуля
Для общих модулей директив нет. Сторону выполнения задают свойства модуля: Клиент (управляемое приложение), Сервер, Вызов сервера, Внешнее соединение, Глобальный, Привилегированный, Повторное использование возвращаемых значений.
Без флажка «Вызов сервера» экспортную процедуру серверного общего модуля нельзя вызвать с клиента. Это одна из самых частых причин ошибки «Процедура или функция с указанным именем не определена».
Как создать процедуру-обработчик через свойства
Обработчики событий вручную лучше не писать: легко ошибиться в имени или параметрах.
- Откройте форму в Конфигураторе.
- Выделите элемент, например кнопку или поле.
- В палитре свойств найдите раздел событий и нужное событие.
- Нажмите кнопку с лупой справа от поля события.
- В модуле формы появится процедура с правильным именем, директивой и параметрами.
Для событий серверной стороны Конфигуратор предложит выбрать, как создать обработчик: только клиентскую процедуру или пару «клиентская процедура + серверная процедура».
Как передать параметры в процедуру: Знач и по ссылке
По умолчанию в 1С параметры передаются по ссылке. Процедура работает с той же переменной, что и вызывающий код. Если присвоить параметру новое значение, оно изменится и снаружи.
Процедура Удвоить(Число)
Число = Число * 2;
КонецПроцедуры
А = 5;
Удвоить(А);
// А теперь равно 10
Ключевое слово Знач включает передачу по значению. Процедура получает копию, и внешняя переменная не меняется.
Процедура Удвоить(Знач Число)
Число = Число * 2;
КонецПроцедуры
А = 5;
Удвоить(А);
// А по-прежнему 5
Подвох с объектами и коллекциями
Знач защищает только саму переменную, а не содержимое объекта. Если передать в процедуру таблицу значений с Знач и добавить в неё строку, строка появится и в исходной таблице. Копию коллекции нужно делать явно, например методом Скопировать() у таблицы значений.
Процедура ДобавитьСтроку(Знач Таблица)
Таблица.Добавить(); // изменит исходную таблицу
Таблица = Новый ТаблицаЗначений; // внешнюю переменную не затронет
КонецПроцедуры
Знач при серверных вызовах
Здесь кроется приём, который знают опытные разработчики. При вызове серверной процедуры с клиента параметры без Знач после выполнения передаются обратно на клиент. Платформа сериализует их дважды: туда и обратно.
Для параметров, которые процедура только читает, ставьте Знач. На больших структурах и массивах это заметно сокращает трафик и время вызова.
Необязательные параметры
Параметру можно задать значение по умолчанию. Оно должно быть литералом: числом, строкой, датой, Истина, Ложь или Неопределено.
Процедура ЗаписатьВЛог(Текст, Уровень = "Инфо", ПоказатьПользователю = Ложь)
// ...
КонецПроцедуры
ЗаписатьВЛог("Старт обмена");
ЗаписатьВЛог("Ошибка загрузки", "Ошибка", Истина);
ЗаписатьВЛог("Пропуск", , Истина); // второй параметр пропущен, будет "Инфо"
Необязательные параметры ставьте в конец списка. Так вызовы читаются без пустых запятых.
Процедура или функция в 1С: в чём разница
Разница одна по сути: функция возвращает значение, процедура — нет.
| Признак | Процедура | Функция |
|---|---|---|
| Ключевые слова | Процедура … КонецПроцедуры | Функция … КонецФункции |
| Возвращает значение | Нет | Да, через Возврат Значение; |
| Можно использовать в выражении | Нет | Да: Сумма = РассчитатьСумму(Цена, Кол); |
Оператор Возврат | Без значения, для досрочного выхода | Со значением |
Функция СуммаСНДС(Сумма, Ставка)
Возврат Сумма + Сумма * Ставка / 100;
КонецФункции
Процедура ПроверитьОстаток(Количество)
Если Количество <= 0 Тогда
Возврат; // досрочный выход из процедуры
КонецЕсли;
// ...
КонецПроцедуры
Пример: СуммаСНДС(1000, 20) вернёт 1200.
Когда что выбирать
- ✅ Процедура — когда нужно что-то сделать: заполнить табличную часть, записать в журнал, показать сообщение.
- ✅ Функция — когда нужно получить результат: сумму, ссылку, признак «можно ли провести».
- ⚠️ Не делайте функцию, которая и меняет данные, и возвращает результат, без явной причины. Такой код трудно читать.
Функцию можно вызвать как процедуру, отбросив результат. Обратное не работает : попытка присвоить «результат» процедуры даст ошибку при выполнении.
Обработка ошибок внутри процедуры: Попытка и Исключение
Если в процедуре может произойти сбой — запись объекта, обращение к файлу, загрузка из внешней системы — оберните опасный участок в Попытка … Исключение … КонецПопытки.
Процедура ЗагрузитьКурс(Валюта, Дата)
Попытка
ВыполнитьЗагрузку(Валюта, Дата);
Исключение
ТекстОшибки = ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
ЗаписьЖурналаРегистрации("ЗагрузкаКурсов",
УровеньЖурналаРегистрации.Ошибка, , , ТекстОшибки);
ВызватьИсключение;
КонецПопытки;
КонецПроцедуры
Что здесь происходит:
ИнформацияОбОшибке()возвращает объект с данными о сбое.ПодробноеПредставлениеОшибкипревращает его в текст со стеком вызовов. В актуальных версиях платформы ту же задачу решаетОбработкаОшибок.ПодробноеПредставлениеОшибки.- Текст пишется в журнал регистрации.
ВызватьИсключение;без параметров пробрасывает исходную ошибку дальше.
Ошибка с собственным текстом
Если нужно прервать выполнение по бизнес-причине, вызовите исключение с текстом:
Если НЕ ЗначениеЗаполнено(Контрагент) Тогда
ВызватьИсключение "Не указан контрагент. Запись невозможна.";
КонецЕсли;
Попытка и транзакции
Шаблон, который рекомендуют стандарты разработки: транзакция начинается до Попытка, а в блоке Исключение обязательно отменяется.
НачатьТранзакцию();
Попытка
ДокументОбъект.Записать(РежимЗаписиДокумента.Проведение);
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
ВызватьИсключение;
КонецПопытки;
Не «глушите» ошибки пустым блоком Исключение. Пользователь не увидит сбоя, данные запишутся не полностью, а причину потом придётся искать неделями.
Как ускорить процедуры в 1С
Медленный код в 1С чаще всего тормозит не из-за алгоритма, а из-за лишних обращений к серверу и к базе.
Меньше серверных вызовов
Каждый вызов серверной процедуры с клиента — это обмен по сети. Пять вызовов подряд в цикле на клиенте работают в разы медленнее одного вызова, который делает всё сразу.
// Плохо: вызов сервера на каждую строку
Для Каждого Строка Из Объект.Товары Цикл
Строка.Цена = ПолучитьЦенуНаСервере(Строка.Номенклатура);
КонецЦикла;
// Хорошо: один вызов на всю таблицу
ЗаполнитьЦеныНаСервере();
&НаСервереБезКонтекста вместо &НаСервере
При вызове &НаСервере платформа передаёт на сервер и обратно данные формы. При &НаСервереБезКонтекста — только параметры. Если процедуре не нужны реквизиты формы, используйте вариант без контекста.
Запросы вне цикла
- 🐢 Запрос в цикле по строкам — тысячи обращений к базе.
- 🚀 Один запрос с отбором по списку (
В (&Список)) или соединением с временной таблицей. - 🚫 Обращение через точку к реквизитам ссылки в цикле (
Строка.Номенклатура.Артикул) — это скрытый запрос на каждую строку. Получайте реквизиты пакетно, одним запросом.
Кэширование через общий модуль
Для функций, которые возвращают редко меняющиеся данные (настройки, константы), заведите общий модуль с флажком Повторное использование возвращаемых значений = «На время сеанса». Повторный вызов с теми же параметрами вернёт результат из кэша без обращения к базе.
Замер производительности
Перед оптимизацией измерьте. В Конфигураторе в режиме отладки включите замер производительности через меню Отладка. Он покажет, сколько времени заняла каждая строка процедуры. Чаще всего 80% времени уходит на две-три строки.
Процедуры в расширении конфигурации
Дорабатывать типовую конфигурацию правильнее через расширение, а не снятием с поддержки. Чтобы подменить или дополнить типовую процедуру, в модуле расширения используют аннотации:
- ⬅️
&Перед("ИмяПроцедуры")— ваш код выполнится до типового. - ➡️
&После("ИмяПроцедуры")— после типового. - 🔄
&Вместо("ИмяПроцедуры")— вместо типового; вызвать исходный код можно черезПродолжитьВызов(). - ✏️
&ИзменениеИКонтроль("ИмяПроцедуры")— правка текста типовой процедуры с контролем изменений при обновлении.
&После("ПередЗаписью")
Процедура Расш1_ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
Если НЕ ЗначениеЗаполнено(Комментарий) Тогда
Комментарий = "Создан через расширение";
КонецЕсли;
КонецПроцедуры
Модуль объекта или формы нужно сначала заимствовать в расширение. Удобнее всего — из контекстного меню модуля в дереве расширения: Конфигуратор сам создаст процедуру с аннотацией и нужными параметрами.