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