Директивы компиляции в управляемых формах 1С

· 9 мин

Содержание

Метод надо выполнить на сервере — ставьте перед ним &НаСервере; показать пользователю окно или открыть форму — &НаКлиенте; посчитать что-то без обращения к реквизитам формы — &НаСервереБезКонтекста. Это и есть выбор директивы компиляции: она сообщает платформе, в каком контексте компилировать и выполнять процедуру или функцию.

Директивы живут в модулях управляемых форм и модулях команд. Строка &НаКлиенте или &НаСервере пишется прямо над Процедура/Функция. Ошибётесь с выбором — получите либо ошибку компиляции («обращение к серверному методу из клиентского контекста недопустимо»), либо лишний обмен данными между клиентом и сервером, который замедляет форму. Разберём все четыре директивы, правила вызовов между ними и как не раздувать клиент-серверный обмен.

Где ставится директива и как выглядит синтаксис

Директива — это строка со знаком & перед объявлением метода:

&НаСервере
Процедура ЗагрузитьДанные()
    // код выполнится на сервере
КонецПроцедуры

&НаКлиенте
Процедура ПриНажатии(Команда)
    ЗагрузитьДанные(); // клиент вызывает сервер
КонецПроцедуры

Применяются директивы в двух местах:

  • 📄 Модуль управляемой формы — обработчики событий формы и её элементов, команды формы.
  • ⌨️ Модуль команды — для самостоятельных команд (например, в подсистемах).

В общих модулях директивы перед методами не ставят: там контекст выполнения задаётся свойствами модуля — флажками Клиент (управляемое приложение), Сервер, Внешнее соединение. Процедура общего модуля доступна там, где модуль скомпилирован.

Если в модуле формы метод объявлен без директивы, он компилируется в серверном контексте и из клиентского кода напрямую не вызывается. Поэтому директиву лучше указывать всегда явно — так код читается однозначно.

Директивы компиляции не нужно путать с инструкциями препроцессора (#Если Клиент Тогда … #КонецЕсли) и с аннотациями расширений (&Перед, &После, &Вместо). О первых — в разделе про совместимость, вторые к выбору места выполнения отношения не имеют.

Четыре директивы и чем они отличаются

В модуле формы доступны четыре директивы. Разница — в двух вещах: где выполняется код и виден ли ему контекст формы (реквизиты, данные, элементы).

ДирективаГде выполняетсяКонтекст формыДоступ к базеДиалоги с пользователем
&НаКлиентена клиентеданетда
&НаСерверена сервереда (чтение и запись)данет
&НаСервереБезКонтекстана серверенетданет
&НаКлиентеНаСервереБезКонтекстаи там, и тамнеттолько на серверной сторонетолько на клиентской стороне

Коротко про каждую:

  • 🖥 &НаКлиенте — работает в сеансе пользователя. Отсюда открывают формы, показывают предупреждения и вопросы (ПоказатьПредупреждение, ПоказатьВопрос), реагируют на нажатия. Запросы к базе и запись объектов тут недоступны.
  • 🗄 &НаСервере — выполняется на сервере и видит весь контекст формы: можно читать и менять реквизиты, выполнять запросы, записывать объекты. Пользователю ничего показать нельзя — диалогов на сервере нет.
  • ⚡ &НаСервереБезКонтекста — тоже на сервере и с доступом к базе, но без данных формы. Метод оперирует только теми параметрами, что ему передали. Самый «дешёвый» серверный вызов.
  • 🔁 &НаКлиентеНаСервереБезКонтекста — метод компилируется для обеих сторон и может вызываться и с клиента, и с сервера. Контекста формы у него нет. Годится для вспомогательной логики, которая одинаково нужна и там, и там.

Главное отличие «с контекстом» и «без контекста» — не в скорости кода, а в объёме данных, которые гоняются между клиентом и сервером. Об этом — дальше.

Почему контекст формы делает вызов дорогим

Когда клиент вызывает метод &НаСервере, платформа перед выполнением упаковывает весь контекст формы (значения реквизитов, таблицы, данные) и отправляет на сервер, а после выполнения забирает обратно. Чем тяжелее форма — тем больше трафик и тем заметнее задержка, особенно на тонком клиенте через медленный канал.

Метод &НаСервереБезКонтекста так не делает: он получает только явно переданные параметры. Контекст не сериализуется и не пересылается. Поэтому для расчётов, которые не трогают реквизиты формы, «без контекста» выигрывает на порядок.

Простой ориентир:

  • нужны и читаются-меняются реквизиты формы → &НаСервере;
  • нужен только результат по переданным параметрам → &НаСервереБезКонтекста.

Частый приём: внутри одного обработчика &НаКлиенте сначала собрать нужные значения в переменные, а потом вызвать &НаСервереБезКонтекста-метод, передав их параметрами. Форма целиком на сервер не поедет.

Как выбрать директиву под конкретную задачу

Выбор сводится к трём вопросам: нужно ли общаться с пользователем, нужен ли доступ к базе, нужны ли данные формы.

Что должен делать метод?

Несколько рабочих правил:

  1. 🧩 По умолчанию стремитесь к &НаСервереБезКонтекста. Если метод можно написать на переданных параметрах — пишите так. Это главный приём оптимизации обмена.
  2. 🖱 Всё, что видит пользователь, — только &НаКлиенте. Открытие форм, диалоги, работа с буфером обмена, печать.
  3. 🗄 Запросы, чтение и запись объектов — только на сервере (&НаСервере или &НаСервереБезКонтекста).
  4. 🔁 Общую утилиту для двух сторон (форматирование строки, пересчёт по формуле) выносите в &НаКлиентеНаСервереБезКонтекста или в общий модуль с нужными флажками.

Правила вызова: что откуда можно вызывать

Направление вызовов между контекстами строго ограничено. Нарушение ловится ещё на этапе компиляции.

  • ✅ Клиент → сервер. &НаКлиенте-метод может вызвать &НаСервере, &НаСервереБезКонтекста и &НаКлиентеНаСервереБезКонтекста.
  • ❌ Сервер → клиент. Из &НаСервере вызвать &НаКлиенте-метод нельзя. Сервер не умеет возвращать управление в клиентский контекст в середине своей работы.
  • ⚠️ Контекстный → без контекста. &НаСервере может вызвать &НаСервереБезКонтекста. А вот &НаСервереБезКонтекста не видит контекст и не может вызвать &НаСервере.
  • ⚠️ &НаКлиентеНаСервереБезКонтекста не может вызывать контекстные методы — у него нет контекста ни на одной стороне.

Отсюда типичный каркас обработчика: клиент собирает данные → зовёт сервер → сервер при необходимости дёргает методы без контекста → результат возвращается на клиент, и уже клиент показывает его пользователю.

Если серверному коду нужно «попросить» пользователя что-то подтвердить, прямого пути нет: сервер завершает работу и возвращает результат, а клиент по нему показывает ПоказатьВопрос и, в зависимости от ответа, делает ещё один серверный вызов.

Вот как выглядит типичный маршрут «клиент собрал → сервер посчитал → клиент показал»:

&НаКлиенте
Процедура Рассчитать(Команда)
    Сумма = РассчитатьСумму(Период, Контрагент);
    Сообщить("Итог: " + Формат(Сумма, "ЧГ=0"));
КонецПроцедуры

&НаСервереБезКонтекста
Функция РассчитатьСумму(Период, Контрагент)
    // запрос к базе; контекст формы не нужен,
    // всё пришло параметрами
    Возврат РезультатЗапроса;
КонецФункции

Здесь клиент передаёт на сервер только два значения, а не всю форму, и сам показывает результат пользователю. Серверной функции контекст не нужен — поэтому &НаСервереБезКонтекста.

Совместимость и разделение клиентского и серверного кода

Директива определяет, где метод выполнится. А вот какой код войдёт в сборку для конкретного типа клиента, управляется инструкциями препроцессора — это отдельный механизм, который часто идёт рядом с директивами.

&НаКлиенте
Процедура ПоказатьФайл()
    #Если ВебКлиент Тогда
        // в веб-клиенте часть файловых операций недоступна
    #Иначе
        // толстый/тонкий клиент
    #КонецЕсли
КонецПроцедуры

Доступные символы препроцессора — Клиент, Сервер, ТонкийКлиент, ВебКлиент, ТолстыйКлиентУправляемоеПриложение, МобильноеПриложениеКлиент и другие. Они позволяют писать код, совместимый с разными типами клиента, не плодя отдельные методы.

Для логики, которая должна жить и на клиенте, и на сервере в одинаковом виде, удобнее &НаКлиентеНаСервереБезКонтекста: один метод, одна точка правки, работает с обеих сторон. Это снижает риск «разъехавшихся» реализаций.

Режим совместимости конфигурации (в свойствах конфигурации) — это про поведение платформы, а не про директивы. Его не настраивают директивами компиляции, не путайте термины.

Директивы и отладка кода на сервере

Директива влияет и на отладку: чтобы встать на точку останова внутри &НаСервере или &НаСервереБезКонтекста-метода, нужна отладка серверного кода.

  • 🧪 В файловом варианте серверный код отлаживается из коробки — всё в одном процессе.
  • 🖧 В клиент-серверном варианте отладку сервера нужно разрешить: в параметрах информационной базы включить отладку , а на кластере — разрешить отладку рабочих процессов (параметр задаётся при запуске службы сервера). Без этого точки останова в серверных методах просто не сработают.

Практический вывод: если точка останова в клиентском обработчике срабатывает, а в вызванном серверном методе — нет, почти всегда дело в том, что отладка сервера не включена, а не в директиве.

Оптимизация: меньше серверных вызовов и меньше контекста

Производительность управляемой формы упирается в две вещи — число серверных вызовов и объём передаваемого контекста. Директивы — главный инструмент влияния на обе.

  • 📉 Сокращайте число вызовов клиент→сервер. Не делайте пять отдельных серверных обращений там, где хватит одного метода, собирающего всё сразу.
  • ⚡ Предпочитайте &НаСервереБезКонтекста, когда данные формы не нужны. Так контекст не пересылается.
  • 🧮 Не тяните тяжёлые реквизиты в контекст зря. Если большая таблица значений нужна только на сервере, подумайте, нельзя ли пересобрать её серверным методом без контекста по переданным параметрам.
  • 🔁 Простые пересчёты (валидация ввода, форматирование) делайте на клиенте или в &НаКлиентеНаСервереБезКонтекста, не гоняя на сервер ради мелочи.
Проверка метода перед выбором директивы
Выполнено: 0 / 5

Типичные ошибки при работе с директивами

Что чаще всего ломает компиляцию или замедляет форму:

  • 🚫 Вызов серверного метода из серверного без контекста. &НаСервереБезКонтекста не видит контекст и не может вызвать &НаСервере. Решение — передавать нужные данные параметрами.
  • 🚫 Попытка показать диалог на сервере. ПоказатьПредупреждение/ПоказатьВопрос работают только на клиенте. Серверный метод возвращает результат, диалог показывает клиент.
  • 🐢 Контекстный серверный вызов там, где хватило бы «без контекста». Форма каждый раз целиком едет на сервер и обратно — лишний трафик. Переведите метод на &НаСервереБезКонтекста, передав параметры.
  • 🚫 Обращение к реквизиту формы из &НаСервереБезКонтекста. Контекста нет — реквизит не виден. Либо меняйте директиву на &НаСервере, либо передавайте значение параметром.
  • 🧷 Метод без директивы, вызываемый с клиента. Без директивы метод компилируется на сервере и из клиента недоступен. Укажите директиву явно.

Если не уверены, нужен ли методу контекст, начните с &НаСервереБезКонтекста и добавляйте доступ к форме только когда это реально потребуется. Так форма по умолчанию получается легче.

Частые вопросы

Какая директива стоит по умолчанию, если её не указать?
В модуле управляемой формы метод без директивы компилируется в серверном контексте и из клиентского кода напрямую не вызывается. Указывайте директиву явно, чтобы код читался однозначно.
Можно ли из `&НаСервере` вызвать `&НаКлиенте`?
Нет. Направление вызова только одностороннее: клиент может звать сервер, но не наоборот. Серверный метод возвращает результат, а клиент уже решает, что показать пользователю.
В чём разница между `&НаСервере` и `&НаСервереБезКонтекста`, если оба на сервере?
В контексте формы. &НаСервере видит реквизиты формы и может их менять, но для этого платформа пересылает весь контекст на сервер и обратно. &НаСервереБезКонтекста контекст не пересылает и работает только с переданными параметрами — поэтому он легче.
Почему в общих модулях нет директив перед методами?
Потому что контекст выполнения общего модуля задаётся его свойствами — флажками Клиент (управляемое приложение), Сервер, Внешнее соединение. Процедура доступна там, где модуль скомпилирован.
Как ускорить форму, если серверных вызовов много?
Сократить их число (собирать данные одним методом вместо нескольких) и переводить методы на &НаСервереБезКонтекста везде, где данные формы не нужны. Это уменьшает и количество обращений, и объём пересылаемого контекста.