Почему директива &НаКлиентеНаСервере работает в командах, но недоступна в формах, и как правильно управлять видимостью элементов?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

В процессе разработки на платформе 1С:Предприятие 8.3 программисты часто сталкиваются с вопросами разделения контекста исполнения кода. Одним из наиболее интересных нюансов является поведение директивы &НаКлиентеНаСервере. В этой статье мы подробно проанализируем, почему эта директива ведет себя по-разному в разных типах модулей, и разберем эффективные способы управления интерфейсом управляемой формы.

Различия в архитектуре модулей команды и формы

Для начала разберем фундаментальную причину, по которой директива &НаКлиентеНаСервере разрешена в модуле команды, но запрещена в модуле формы. Проблема кроется в понятии контекста.

Модуль команды: Здесь контекст формы (данные реквизитов, объект, списки) отсутствует в принципе. Платформа воспринимает директиву &НаКлиентеНаСервере как универсальный переключатель. Код просто компилируется в двух экземплярах: один для клиента, другой для сервера. Поскольку данных формы в этом модуле нет, "тянуть" на сервер нечего, и лишнего трафика не возникает.

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

Механика работы директивы &НаКлиентеНаСервереБезКонтекста

Проанализируем ситуацию с компиляцией. Важно понимать, что процедура с такой директивой — это не один метод, а два разных фрагмента кода, созданных на этапе компиляции.

Рассмотрим пример, как правильно писать универсальные процедуры, чтобы не вызвать ошибку выполнения на клиенте:


&НаКлиентеНаСервереБезКонтекста
Процедура УниверсальнаяОбработка(Знач Параметр)
    // Этот код выполнится и там, и там
    Сообщение = "Выполняем обработку...";
    
    #Если Сервер Тогда
        // Код, работающий только на сервере (например, работа с БД)
        ЭлементОбъекта = Справочники.Номенклатура.НайтиПоНаименованию(Параметр);
    #КонецЕсли

    #Если Клиент Тогда
        // Код, специфичный для клиента
        ПоказатьОповещениеПользователя(Сообщение);
    #КонецЕсли
КонецПроцедуры

Если внутри такой процедуры использовать объекты, доступные только на сервере (например, Запрос), без инструкции препроцессора #Если Сервер Тогда, то при попытке выполнить этот же код на клиенте система выдаст критическую ошибку.

Паттерн «Псевдоконтекст»: передача формы как параметра

Выясним, как можно обойти отсутствие контекста в бесконтекстных вызовах. Существует эффективный прием, который иногда называют "передачей псевдоконтекста". Вы можете передать саму форму в качестве параметра процедуры.

Рассмотрим ситуацию, когда нам нужно изменить видимость элементов формы в универсальном методе:


&НаКлиенте
Процедура КомандаВыполнить(Команда)
    УниверсальноеУправлениеИнтерфейсом(ЭтаФорма, Истина);
КонецПроцедуры

&НаКлиентеНаСервереБезКонтекста
Процедура УниверсальноеУправлениеИнтерфейсом(Форма, ЗначениеВидимости)
    // Мы получили доступ к коллекции элементов через параметр
    ЭлементыФормы = Форма.Элементы;
    ЭлементыФормы.ГруппаСлужебнаяИнформация.Видимость = ЗначениеВидимости;
КонецПроцедуры

Преимущества данного подхода:

  1. Экономия трафика: В отличие от полноценного контекстного вызова (&НаСервере), при передаче ЭтаФорма в бесконтекстный метод передается только ссылка на структуру интерфейса, а не все данные реквизитов (объекта, табличных частей и т.д.).
  2. Лаконичность кода: Вы можете описывать логику поведения интерфейса в одном месте, вызывая её как с клиента, так и с сервера.

Особенности управления видимостью (версии 8.3.7 и выше)

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

Начиная с версии 8.3.7, платформа была значительно оптимизирована. Теперь изменение видимости простых элементов (полей ввода, кнопок) старается выполняться на клиенте без обращения к серверу. Однако есть исключения, когда серверный вызов неизбежен:

  1. Группы формы: Группа — это не просто контейнер, а сложный элемент, влияющий на расчет топологии (геометрии) всей формы. При скрытии группы платформа часто обращается к серверу, чтобы пересчитать, как должны переместиться остальные элементы.
  2. Функциональные опции: Если видимость элемента привязана к функциональной опции, вызов сервера произойдет обязательно, так как проверка прав и состояния опций — это прерогатива сервера и базы данных.
  3. Динамические списки: Это самая "дорогая" операция. Изменение видимости колонок списка инициирует серверный звонок, так как платформе нужно перестроить SQL-запрос к базе данных, чтобы не тянуть лишние колонки.

Рекомендации по оптимизации

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

Во-первых, если задача заключается исключительно в визуальном изменении (скрыть одну кнопку или заблокировать поле), всегда отдавайте приоритет процедурам &НаКлиенте. Помните, что даже самый быстрый бесконтекстный вызов сервера — это сериализация данных в XML/JSON, сетевой пакет и обратная десериализация. Эти накладные расходы могут составлять 100-200 мс, что при частом использовании сделает интерфейс "дерганым".

Во-вторых, используйте &НаКлиентеНаСервереБезКонтекста только тогда, когда алгоритм действительно идентичен для обеих сторон. Например, расчет суммы по строке (Цена * Количество), который должен срабатывать и при вводе данных пользователем (на клиенте), и при программном заполнении документа (на сервере).

В-третьих, если вам все же нужно изменить видимость множества элементов, связанных сложной логикой, лучше сгруппировать их в одну процедуру. Передача формы как параметра в бесконтекстный метод &НаКлиентеНаСервереБезКонтекста в данном случае будет "золотой серединой" между удобством разработки и производительностью системы. Для интерактивного анализа и изменения параметров отображения элементов прямо во время работы системы можно использовать инструмент редактирования форм в режиме 1С:Предприятие.

← На главную