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