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