Вызов процедуры во встроенном языке 1С 8.3: модули, контекст, директивы и разбор ошибок
Содержание
В 1С к процедуре обращаются по имени со скобками: ЗаполнитьТаблицу(Дата, Склад);. Если процедура лежит в том же модуле, хватает имени. Если в другом, её объявляют с ключевым словом Экспорт и вызывают через модуль: РаботаСЦенами.ЗаполнитьТаблицу(Дата, Склад); для общего модуля или Справочники.Номенклатура.ЗаполнитьТаблицу(...) для модуля менеджера.
Способ вызова выбирают по месту, где живёт процедура. Прямой вызов по имени работает внутри модуля. Через имя модуля обращаются к общим модулям и модулям менеджеров. Через объект вызывают экспортные методы модуля объекта и формы. Динамический вызов через Выполнить() нужен, когда имя процедуры известно только во время работы программы. Дальше всё это по порядку, с примерами для платформы 8.3 и управляемых форм.
Синтаксис вызова процедуры в модуле 1С
Процедура объявляется так:
Процедура ПересчитатьСумму(Количество, Цена, Сумма)
Сумма = Количество * Цена;
КонецПроцедуры
Вызов — отдельный оператор с точкой с запятой:
Сумма = 0;
ПересчитатьСумму(5, 120, Сумма);
// Сумма = 600
Главное отличие процедуры от функции: процедура не возвращает значение. Её нельзя поставить в правую часть присваивания или в условие. Строка Итог = ПересчитатьСумму(5, 120, Сумма); не скомпилируется: модуль покажет ошибку Использование процедуры как функции.
С функцией наоборот: её можно вызвать и как выражение, и как процедуру. Во втором случае возвращённое значение просто теряется.
Функция Наценка(Цена, Процент)
Возврат Цена * (1 + Процент / 100);
КонецФункции
НоваяЦена = Наценка(1000, 25); // 1250
Наценка(1000, 25); // допустимо, результат отброшен
Несколько правил, о которых часто спрашивают новички:
- 📌 Регистр букв в имени не важен:
пересчитатьсумму()иПересчитатьСумму()— один и тот же вызов. - 📌 Скобки обязательны даже без параметров:
ОбновитьИтоги();. - 📌 В 8.3 процедуру можно вызвать выше по тексту, чем она объявлена: компилятор видит весь модуль целиком. Предварительное объявление через
Далеебыло нужно в 1С 7.7, в восьмёрке без него обходятся. - 📌 Досрочно выйти из процедуры можно оператором
Возврат;без значения.
| Что вызываем | Где объявлено | Как обращаться |
|---|---|---|
| Процедура того же модуля | этот же модуль | ИмяПроцедуры(...) |
| Процедура общего модуля | общий модуль, Экспорт | ИмяМодуля.ИмяПроцедуры(...) |
| Метод модуля менеджера | модуль менеджера, Экспорт | Документы.ПриходТовара.ИмяПроцедуры(...) |
| Метод модуля объекта | модуль объекта, Экспорт | ДокументОбъект.ИмяПроцедуры(...) |
| Метод формы | модуль формы, Экспорт, &НаКлиенте | Форма.ИмяПроцедуры(...) |
| Глобальный общий модуль | общий модуль с флагом «Глобальный» | ИмяПроцедуры(...) без имени модуля |
Как передавать параметры в процедуру
По умолчанию параметр передаётся по ссылке. Процедура получает не копию, а саму переменную вызывающего кода. Если внутри присвоить параметру новое значение, оно окажется и снаружи — так в примере выше работала Сумма.
Чтобы процедура не трогала исходную переменную, перед параметром ставят Знач:
Процедура Округлить(Знач Число, Результат)
Число = Окр(Число, 2); // меняется только локальная копия
Результат = Число;
КонецПроцедуры
С объектами есть тонкость. Таблица значений, структура или массив, переданные даже через Знач, меняются внутри процедуры: копируется ссылка на объект, а не сам объект. Знач защищает только от замены переменной целиком, например от Таблица = Новый ТаблицаЗначений.
Необязательные параметры и значения по умолчанию
Параметру можно задать значение по умолчанию. Тогда при вызове его разрешено пропустить:
Процедура ЗаписатьВЖурнал(Текст, Уровень = "Информация", Отправить = Ложь)
// ...
КонецПроцедуры
ЗаписатьВЖурнал("Загрузка завершена");
ЗаписатьВЖурнал("Нет связи", "Ошибка");
ЗаписатьВЖурнал("Нет связи", , Истина); // второй пропущен запятой
Пропуск через пустое место между запятыми работает только для параметров со значением по умолчанию. Если пропустить обязательный параметр, вместо него придёт Неопределено, и процедура может упасть уже в своей логике.
Когда параметров много
Если параметров больше пяти-шести, их удобнее собрать в структуру и передать одним аргументом. Так поступают в типовых конфигурациях на БСП:
Параметры = Новый Структура;
Параметры.Вставить("Организация", Организация);
Параметры.Вставить("Период", ТекущаяДатаСеанса());
Параметры.Вставить("ТолькоПроведенные", Истина);
СформироватьДвижения(Параметры);
Порядок аргументов перестаёт иметь значение, а новый параметр добавляется без правки всех мест вызова.
Область видимости: из какого модуля процедура доступна
Без слова Экспорт процедура видна только внутри своего модуля. Это обычная практика: служебные процедуры прячут, наружу выставляют только программный интерфейс.
Процедура ПровестиПоРегистрам(Отказ) Экспорт
ПроверитьОстатки(Отказ); // неэкспортная, вызывается только отсюда
КонецПроцедуры
Где что видно:
- 🔹 Модуль формы — процедуры доступны только этой форме. Снаружи можно вызвать экспортную клиентскую процедуру, если есть ссылка на открытую форму.
- 🔹 Модуль объекта — экспортные методы вызываются у экземпляра:
Объект = Ссылка.ПолучитьОбъект(); Объект.ЗаполнитьПоОснованию(...). - 🔹 Модуль менеджера — экспортные методы вызываются без экземпляра, через менеджер:
Справочники.Контрагенты.НайтиПоИНН(ИНН). - 🔹 Общий модуль — экспортные методы доступны всей конфигурации с учётом флагов контекста (о них ниже).
- 🔹 Модуль приложения и модуль сеанса — используются для обработчиков событий запуска, а не как библиотека.
Переменные модуля, объявленные через Перем в начале модуля, видны всем процедурам этого модуля. Переменные, объявленные внутри процедуры, живут только до её конца.
Имя процедуры в общем модуле не должно совпадать с именем метода глобального контекста. Если назвать процедуру Сообщить, при вызове без имени модуля будет непонятно, чей метод сработает. Всегда обращайтесь через имя модуля.
Клиент и сервер: как обратиться к процедуре из другого контекста
В управляемом приложении код выполняется либо на клиенте, либо на сервере. Контекст в модуле формы задают директивы компиляции перед процедурой:
| Директива | Где выполняется | Доступ к данным формы |
|---|---|---|
&НаКлиенте | клиент | есть |
&НаСервере | сервер | есть, форма передаётся на сервер |
&НаСервереБезКонтекста | сервер | нет, только переданные параметры |
&НаКлиентеНаСервереБезКонтекста | там, откуда вызвали | нет |
Из клиентской процедуры серверную вызывают обычным образом, платформа сама организует вызов сервера:
&НаКлиенте
Процедура Заполнить(Команда)
ЗаполнитьНаСервере();
КонецПроцедуры
&НаСервере
Процедура ЗаполнитьНаСервере()
Объект.Товары.Очистить();
// запрос к базе и заполнение табличной части
КонецПроцедуры
Обратного пути нет: серверная процедура не может вызвать клиентскую. Если серверу нужно что-то показать пользователю, он возвращает результат, а показывает уже клиентский код.
Почему стоит выбирать «БезКонтекста»
Вызов &НаСервере передаёт на сервер всю форму с реквизитами и табличными частями, а потом возвращает её обратно. На форме с тысячей строк это заметно тормозит. Если процедуре нужны только два значения, используйте &НаСервереБезКонтекста и передайте их параметрами:
&НаСервереБезКонтекста
Функция ОстатокТовара(Номенклатура, Склад)
Запрос = Новый Запрос(
"ВЫБРАТЬ ЕСТЬNULL(СУММА(Т.КоличествоОстаток), 0) КАК Остаток
|ИЗ РегистрНакопления.ТоварыНаСкладах.Остатки(, Номенклатура = &Н И Склад = &С) КАК Т");
Запрос.УстановитьПараметр("Н", Номенклатура);
Запрос.УстановитьПараметр("С", Склад);
Возврат Запрос.Выполнить().Выгрузить()[0].Остаток;
КонецФункции
Имя регистра в примере условное, подставьте своё.
При вызове сервера с клиента параметры, переданные по ссылке, после выполнения передаются обратно на клиент. Если возвращать их не нужно, ставьте Знач — меньше данных пойдёт по сети.
Флаги общих модулей
В свойствах общего модуля в Конфигураторе стоят флажки «Клиент (управляемое приложение)», «Сервер», «Вызов сервера», «Внешнее соединение», «Привилегированный», «Глобальный». От них зависит, откуда процедура видна:
- ✅ Модуль с флагом «Сервер» без «Вызов сервера» виден только из серверного кода. С клиента его процедуру не вызвать.
- ✅ Чтобы клиент мог обратиться к серверной процедуре общего модуля, нужен флаг «Вызов сервера». Типовые конфигурации называют такие модули с суффиксом
ВызовСервера. - ✅ Модуль с флагом «Клиент» нужен для процедур, которые работают с интерфейсом: открывают формы, показывают вопросы.
Динамический вызов и асинхронные процедуры
Иногда имя процедуры приходит из настройки или строки. Тогда вызывают через Выполнить():
ИмяМетода = "ОбменДанными.ВыгрузитьКонтрагентов";
Выполнить(ИмяМетода + "()");
Для функции используют Вычислить(), он возвращает значение:
Результат = Вычислить("РаботаСЦенами.ТекущаяЦена(Номенклатура)");
Не собирайте строку для Выполнить() из данных, которые вводит пользователь или присылает внешняя система. Такая строка выполнит любой код с правами текущего сеанса. Если строку всё же формируют снаружи, включайте безопасный режим через УстановитьБезопасныйРежим(Истина). В конфигурациях на БСП есть готовые обёртки в общем модуле ОбщегоНазначения, например ВыполнитьМетодКонфигурации — они проверяют имя метода перед вызовом.
Обращение к процедуре-обработчику через ОписаниеОповещения
В клиентском коде без модальных окон процедуру часто вызывают не напрямую, а передают её имя платформе. Она вызовет процедуру позже, когда пользователь ответит на вопрос или закроет форму:
&НаКлиенте
Процедура Удалить(Команда)
Оповещение = Новый ОписаниеОповещения("УдалитьЗавершение", ЭтотОбъект);
ПоказатьВопрос(Оповещение, "Удалить строку?", РежимДиалогаВопрос.ДаНет);
КонецПроцедуры
&НаКлиенте
Процедура УдалитьЗавершение(Результат, ДополнительныеПараметры) Экспорт
Если Результат = КодВозвратаДиалога.Да Тогда
// удаление
КонецЕсли;
КонецПроцедуры
Процедура-обработчик обязана быть экспортной, иначе платформа её не найдёт. Количество параметров должно совпадать с тем, что передаёт метод: для ПоказатьВопрос это результат и дополнительные параметры.
Чем отличается вызов в разных версиях платформы
Синтаксис самого вызова со времён 8.0 почти не менялся. Менялось окружение вокруг него.
| Версия | Что изменилось для вызова процедур |
|---|---|
| 1С 7.7 | процедуру, вызванную выше объявления, требовалось объявить заранее через Далее |
| 8.0–8.1, обычные формы | весь код формы на клиенте, директив компиляции нет |
| 8.2, управляемые формы | появились директивы &НаКлиенте, &НаСервере, флаги общих модулей, вызов сервера |
| 8.3, режим без модальности | модальные вызовы заменяют на ОписаниеОповещения и экспортные обработчики |
| 8.3.18 и новее | асинхронные процедуры и функции: ключевые слова Асинх и Ждать |
Асинхронный вариант делает код линейным, без отдельной процедуры-обработчика:
&НаКлиенте
Асинх Процедура Удалить(Команда)
Ответ = Ждать ВопросАсинх("Удалить строку?", РежимДиалогаВопрос.ДаНет);
Если Ответ = КодВозвратаДиалога.Да Тогда
// удаление
КонецЕсли;
КонецПроцедуры
Асинх и Ждать работают, только если в свойствах конфигурации режим совместимости не ниже 8.3.18. В базе с более старым режимом совместимости модуль просто не скомпилируется.
В конфигурациях на обычных формах (старые УПП, Комплексная 1.1) директивы клиента и сервера в модулях форм не используются. Там процедура формы вызывает процедуру модуля объекта напрямую.
Отладка вызова процедуры в Конфигураторе
Чтобы увидеть, доходит ли выполнение до процедуры и с какими параметрами:
- Откройте модуль, установите курсор на первую строку процедуры и нажмите
F9— появится точка останова. - Запустите отладку:
Отладка → Начать отладкуилиF5. - Выполните в режиме 1С:Предприятие действие, которое вызывает процедуру.
- Когда выполнение остановится, наведите курсор на параметр — подсказка покажет значение. Для таблиц и структур удобнее табло или окно «Вычислить выражение» (
Shift+F9). - Шагайте:
F11— зайти внутрь вызываемой процедуры,F10— выполнить строку без захода,Shift+F11— выйти из текущей процедуры. - Окно «Стек вызовов» (
Ctrl+Alt+C) показывает цепочку: какая процедура вызвала текущую и из какого модуля.
Для перехода от вызова к объявлению поставьте курсор на имя и нажмите F12. Если переход не срабатывает, процедура не найдена там, где вы ожидаете, — это уже подсказка к ошибке.
В клиент-серверной базе точки останова в серверном коде не срабатывают, пока на сервере 1С не разрешена отладка. Её включают параметром -debug в строке запуска службы агента сервера. Перезапуск службы обрывает все сеансы пользователей, поэтому делайте его вне рабочего времени. В файловой базе серверный код отлаживается без дополнительных настроек.
Перед запуском полезно проверить модуль: Ctrl+F7 выполняет синтаксический контроль и сразу показывает ошибки вызова, которые ловятся при компиляции.
Ошибки при обращении к процедуре и как их исправить
Сообщения платформы короткие, но по ним точно понятно, что не так. Выберите свой текст:
После переименования процедуры найдите все места вызова через Правка → Глобальный поиск (Ctrl+Shift+F) по старому имени. Синтаксический контроль модуля проверяет только сам модуль, поэтому для всей конфигурации запустите Конфигурация → Проверка конфигурации.
Можно ли вызвать процедуру модуля формы из общего модуля?
Как вызвать процедуру внешней обработки?
ВнешниеОбработки.Создать(...) и вызовите экспортную процедуру её модуля объекта: например Обработка.ЗагрузитьДанные().Можно ли передать процедуру как параметр в другую процедуру?
Выполнить() или объект ОписаниеОповещения, который потом запускают через ВыполнитьОбработкуОповещения.Влияет ли количество вызовов сервера на скорость?
Почему процедура вызывается, но изменения параметра не видны снаружи?
Знач. Уберите его или верните значение из функции.