Директивы компиляции в управляемых формах 1С
Содержание
Метод надо выполнить на сервере — ставьте перед ним &НаСервере; показать пользователю окно или открыть форму — &НаКлиенте; посчитать что-то без обращения к реквизитам формы — &НаСервереБезКонтекста. Это и есть выбор директивы компиляции: она сообщает платформе, в каком контексте компилировать и выполнять процедуру или функцию.
Директивы живут в модулях управляемых форм и модулях команд. Строка &НаКлиенте или &НаСервере пишется прямо над Процедура/Функция. Ошибётесь с выбором — получите либо ошибку компиляции («обращение к серверному методу из клиентского контекста недопустимо»), либо лишний обмен данными между клиентом и сервером, который замедляет форму. Разберём все четыре директивы, правила вызовов между ними и как не раздувать клиент-серверный обмен.
Где ставится директива и как выглядит синтаксис
Директива — это строка со знаком & перед объявлением метода:
&НаСервере
Процедура ЗагрузитьДанные()
// код выполнится на сервере
КонецПроцедуры
&НаКлиенте
Процедура ПриНажатии(Команда)
ЗагрузитьДанные(); // клиент вызывает сервер
КонецПроцедуры
Применяются директивы в двух местах:
- 📄 Модуль управляемой формы — обработчики событий формы и её элементов, команды формы.
- ⌨️ Модуль команды — для самостоятельных команд (например, в подсистемах).
В общих модулях директивы перед методами не ставят: там контекст выполнения задаётся свойствами модуля — флажками Клиент (управляемое приложение), Сервер, Внешнее соединение. Процедура общего модуля доступна там, где модуль скомпилирован.
Если в модуле формы метод объявлен без директивы, он компилируется в серверном контексте и из клиентского кода напрямую не вызывается. Поэтому директиву лучше указывать всегда явно — так код читается однозначно.
Директивы компиляции не нужно путать с инструкциями препроцессора (#Если Клиент Тогда … #КонецЕсли) и с аннотациями расширений (&Перед, &После, &Вместо). О первых — в разделе про совместимость, вторые к выбору места выполнения отношения не имеют.
Четыре директивы и чем они отличаются
В модуле формы доступны четыре директивы. Разница — в двух вещах: где выполняется код и виден ли ему контекст формы (реквизиты, данные, элементы).
| Директива | Где выполняется | Контекст формы | Доступ к базе | Диалоги с пользователем |
|---|---|---|---|---|
&НаКлиенте | на клиенте | да | нет | да |
&НаСервере | на сервере | да (чтение и запись) | да | нет |
&НаСервереБезКонтекста | на сервере | нет | да | нет |
&НаКлиентеНаСервереБезКонтекста | и там, и там | нет | только на серверной стороне | только на клиентской стороне |
Коротко про каждую:
- 🖥
&НаКлиенте— работает в сеансе пользователя. Отсюда открывают формы, показывают предупреждения и вопросы (ПоказатьПредупреждение,ПоказатьВопрос), реагируют на нажатия. Запросы к базе и запись объектов тут недоступны. - 🗄
&НаСервере— выполняется на сервере и видит весь контекст формы: можно читать и менять реквизиты, выполнять запросы, записывать объекты. Пользователю ничего показать нельзя — диалогов на сервере нет. - ⚡
&НаСервереБезКонтекста— тоже на сервере и с доступом к базе, но без данных формы. Метод оперирует только теми параметрами, что ему передали. Самый «дешёвый» серверный вызов. - 🔁
&НаКлиентеНаСервереБезКонтекста— метод компилируется для обеих сторон и может вызываться и с клиента, и с сервера. Контекста формы у него нет. Годится для вспомогательной логики, которая одинаково нужна и там, и там.
Главное отличие «с контекстом» и «без контекста» — не в скорости кода, а в объёме данных, которые гоняются между клиентом и сервером. Об этом — дальше.
Почему контекст формы делает вызов дорогим
Когда клиент вызывает метод &НаСервере, платформа перед выполнением упаковывает весь контекст формы (значения реквизитов, таблицы, данные) и отправляет на сервер, а после выполнения забирает обратно. Чем тяжелее форма — тем больше трафик и тем заметнее задержка, особенно на тонком клиенте через медленный канал.
Метод &НаСервереБезКонтекста так не делает: он получает только явно переданные параметры. Контекст не сериализуется и не пересылается. Поэтому для расчётов, которые не трогают реквизиты формы, «без контекста» выигрывает на порядок.
Простой ориентир:
- нужны и читаются-меняются реквизиты формы →
&НаСервере; - нужен только результат по переданным параметрам →
&НаСервереБезКонтекста.
Частый приём: внутри одного обработчика &НаКлиенте сначала собрать нужные значения в переменные, а потом вызвать &НаСервереБезКонтекста-метод, передав их параметрами. Форма целиком на сервер не поедет.
Как выбрать директиву под конкретную задачу
Выбор сводится к трём вопросам: нужно ли общаться с пользователем, нужен ли доступ к базе, нужны ли данные формы.
&НаКлиенте. Запрос к базе отсюда сделайте отдельным серверным вызовом.&НаСервере. Метод увидит контекст формы и сможет его изменить.&НаСервереБезКонтекста — самый лёгкий вызов, форма на сервер не пересылается.&НаКлиентеНаСервереБезКонтекста — один метод для обеих сторон.Несколько рабочих правил:
- 🧩 По умолчанию стремитесь к
&НаСервереБезКонтекста. Если метод можно написать на переданных параметрах — пишите так. Это главный приём оптимизации обмена. - 🖱 Всё, что видит пользователь, — только
&НаКлиенте. Открытие форм, диалоги, работа с буфером обмена, печать. - 🗄 Запросы, чтение и запись объектов — только на сервере (
&НаСервереили&НаСервереБезКонтекста). - 🔁 Общую утилиту для двух сторон (форматирование строки, пересчёт по формуле) выносите в
&НаКлиентеНаСервереБезКонтекстаили в общий модуль с нужными флажками.
Правила вызова: что откуда можно вызывать
Направление вызовов между контекстами строго ограничено. Нарушение ловится ещё на этапе компиляции.
- ✅ Клиент → сервер.
&НаКлиенте-метод может вызвать&НаСервере,&НаСервереБезКонтекстаи&НаКлиентеНаСервереБезКонтекста. - ❌ Сервер → клиент. Из
&НаСерверевызвать&НаКлиенте-метод нельзя. Сервер не умеет возвращать управление в клиентский контекст в середине своей работы. - ⚠️ Контекстный → без контекста.
&НаСервереможет вызвать&НаСервереБезКонтекста. А вот&НаСервереБезКонтекстане видит контекст и не может вызвать&НаСервере. - ⚠️
&НаКлиентеНаСервереБезКонтекстане может вызывать контекстные методы — у него нет контекста ни на одной стороне.
Отсюда типичный каркас обработчика: клиент собирает данные → зовёт сервер → сервер при необходимости дёргает методы без контекста → результат возвращается на клиент, и уже клиент показывает его пользователю.
Если серверному коду нужно «попросить» пользователя что-то подтвердить, прямого пути нет: сервер завершает работу и возвращает результат, а клиент по нему показывает ПоказатьВопрос и, в зависимости от ответа, делает ещё один серверный вызов.
Вот как выглядит типичный маршрут «клиент собрал → сервер посчитал → клиент показал»:
&НаКлиенте
Процедура Рассчитать(Команда)
Сумма = РассчитатьСумму(Период, Контрагент);
Сообщить("Итог: " + Формат(Сумма, "ЧГ=0"));
КонецПроцедуры
&НаСервереБезКонтекста
Функция РассчитатьСумму(Период, Контрагент)
// запрос к базе; контекст формы не нужен,
// всё пришло параметрами
Возврат РезультатЗапроса;
КонецФункции
Здесь клиент передаёт на сервер только два значения, а не всю форму, и сам показывает результат пользователю. Серверной функции контекст не нужен — поэтому &НаСервереБезКонтекста.
Совместимость и разделение клиентского и серверного кода
Директива определяет, где метод выполнится. А вот какой код войдёт в сборку для конкретного типа клиента, управляется инструкциями препроцессора — это отдельный механизм, который часто идёт рядом с директивами.
&НаКлиенте
Процедура ПоказатьФайл()
#Если ВебКлиент Тогда
// в веб-клиенте часть файловых операций недоступна
#Иначе
// толстый/тонкий клиент
#КонецЕсли
КонецПроцедуры
Доступные символы препроцессора — Клиент, Сервер, ТонкийКлиент, ВебКлиент, ТолстыйКлиентУправляемоеПриложение, МобильноеПриложениеКлиент и другие. Они позволяют писать код, совместимый с разными типами клиента, не плодя отдельные методы.
Для логики, которая должна жить и на клиенте, и на сервере в одинаковом виде, удобнее &НаКлиентеНаСервереБезКонтекста: один метод, одна точка правки, работает с обеих сторон. Это снижает риск «разъехавшихся» реализаций.
Режим совместимости конфигурации (в свойствах конфигурации) — это про поведение платформы, а не про директивы. Его не настраивают директивами компиляции, не путайте термины.
Директивы и отладка кода на сервере
Директива влияет и на отладку: чтобы встать на точку останова внутри &НаСервере или &НаСервереБезКонтекста-метода, нужна отладка серверного кода.
- 🧪 В файловом варианте серверный код отлаживается из коробки — всё в одном процессе.
- 🖧 В клиент-серверном варианте отладку сервера нужно разрешить: в параметрах информационной базы включить отладку , а на кластере — разрешить отладку рабочих процессов (параметр задаётся при запуске службы сервера). Без этого точки останова в серверных методах просто не сработают.
Практический вывод: если точка останова в клиентском обработчике срабатывает, а в вызванном серверном методе — нет, почти всегда дело в том, что отладка сервера не включена, а не в директиве.
Оптимизация: меньше серверных вызовов и меньше контекста
Производительность управляемой формы упирается в две вещи — число серверных вызовов и объём передаваемого контекста. Директивы — главный инструмент влияния на обе.
- 📉 Сокращайте число вызовов клиент→сервер. Не делайте пять отдельных серверных обращений там, где хватит одного метода, собирающего всё сразу.
- ⚡ Предпочитайте
&НаСервереБезКонтекста, когда данные формы не нужны. Так контекст не пересылается. - 🧮 Не тяните тяжёлые реквизиты в контекст зря. Если большая таблица значений нужна только на сервере, подумайте, нельзя ли пересобрать её серверным методом без контекста по переданным параметрам.
- 🔁 Простые пересчёты (валидация ввода, форматирование) делайте на клиенте или в
&НаКлиентеНаСервереБезКонтекста, не гоняя на сервер ради мелочи.
Типичные ошибки при работе с директивами
Что чаще всего ломает компиляцию или замедляет форму:
- 🚫 Вызов серверного метода из серверного без контекста.
&НаСервереБезКонтекстане видит контекст и не может вызвать&НаСервере. Решение — передавать нужные данные параметрами. - 🚫 Попытка показать диалог на сервере.
ПоказатьПредупреждение/ПоказатьВопросработают только на клиенте. Серверный метод возвращает результат, диалог показывает клиент. - 🐢 Контекстный серверный вызов там, где хватило бы «без контекста». Форма каждый раз целиком едет на сервер и обратно — лишний трафик. Переведите метод на
&НаСервереБезКонтекста, передав параметры. - 🚫 Обращение к реквизиту формы из
&НаСервереБезКонтекста. Контекста нет — реквизит не виден. Либо меняйте директиву на&НаСервере, либо передавайте значение параметром. - 🧷 Метод без директивы, вызываемый с клиента. Без директивы метод компилируется на сервере и из клиента недоступен. Укажите директиву явно.
Если не уверены, нужен ли методу контекст, начните с &НаСервереБезКонтекста и добавляйте доступ к форме только когда это реально потребуется. Так форма по умолчанию получается легче.
Частые вопросы
Какая директива стоит по умолчанию, если её не указать?
Можно ли из `&НаСервере` вызвать `&НаКлиенте`?
В чём разница между `&НаСервере` и `&НаСервереБезКонтекста`, если оба на сервере?
&НаСервере видит реквизиты формы и может их менять, но для этого платформа пересылает весь контекст на сервер и обратно. &НаСервереБезКонтекста контекст не пересылает и работает только с переданными параметрами — поэтому он легче.Почему в общих модулях нет директив перед методами?
Клиент (управляемое приложение), Сервер, Внешнее соединение. Процедура доступна там, где модуль скомпилирован.Как ускорить форму, если серверных вызовов много?
&НаСервереБезКонтекста везде, где данные формы не нужны. Это уменьшает и количество обращений, и объём пересылаемого контекста.