В процессе разработки на платформе 1С:Предприятие 8.3 программисты часто сталкиваются с вопросами разделения контекста исполнения кода. Одним из наиболее интересных нюансов является поведение директивы &НаКлиентеНаСервере. В этой статье мы подробно проанализируем, почему эта директива ведет себя по-разному в разных типах модулей, и разберем эффективные способы управления интерфейсом управляемой формы.
Для начала разберем фундаментальную причину, по которой директива &НаКлиентеНаСервере разрешена в модуле команды, но запрещена в модуле формы. Проблема кроется в понятии контекста.
Модуль команды: Здесь контекст формы (данные реквизитов, объект, списки) отсутствует в принципе. Платформа воспринимает директиву &НаКлиентеНаСервере как универсальный переключатель. Код просто компилируется в двух экземплярах: один для клиента, другой для сервера. Поскольку данных формы в этом модуле нет, "тянуть" на сервер нечего, и лишнего трафика не возникает.
Модуль управляемой формы: В форме контекст существует всегда — это реквизиты, элементы и сам объект. Если бы платформа разрешила использовать &НаКлиентеНаСервере в модуле формы, возникла бы неопределенность: должен ли этот метод при серверном вызове передавать на сервер все данные формы (контекстный вызов) или нет? Чтобы исключить путаницу и предотвратить случайные "тяжелые" вызовы, разработчики платформы ввели обязательное уточнение. В модуле формы вы должны явно указать &НаКлиентеНаСервереБезКонтекста, тем самым подтверждая, что понимаете: данные формы в этот метод автоматически переданы не будут.
Проанализируем ситуацию с компиляцией. Важно понимать, что процедура с такой директивой — это не один метод, а два разных фрагмента кода, созданных на этапе компиляции.
Рассмотрим пример, как правильно писать универсальные процедуры, чтобы не вызвать ошибку выполнения на клиенте:
&НаКлиентеНаСервереБезКонтекста
Процедура УниверсальнаяОбработка(Знач Параметр)
// Этот код выполнится и там, и там
Сообщение = "Выполняем обработку...";
#Если Сервер Тогда
// Код, работающий только на сервере (например, работа с БД)
ЭлементОбъекта = Справочники.Номенклатура.НайтиПоНаименованию(Параметр);
#КонецЕсли
#Если Клиент Тогда
// Код, специфичный для клиента
ПоказатьОповещениеПользователя(Сообщение);
#КонецЕсли
КонецПроцедуры
Если внутри такой процедуры использовать объекты, доступные только на сервере (например, Запрос), без инструкции препроцессора #Если Сервер Тогда, то при попытке выполнить этот же код на клиенте система выдаст критическую ошибку.
Выясним, как можно обойти отсутствие контекста в бесконтекстных вызовах. Существует эффективный прием, который иногда называют "передачей псевдоконтекста". Вы можете передать саму форму в качестве параметра процедуры.
Рассмотрим ситуацию, когда нам нужно изменить видимость элементов формы в универсальном методе:
&НаКлиенте
Процедура КомандаВыполнить(Команда)
УниверсальноеУправлениеИнтерфейсом(ЭтаФорма, Истина);
КонецПроцедуры
&НаКлиентеНаСервереБезКонтекста
Процедура УниверсальноеУправлениеИнтерфейсом(Форма, ЗначениеВидимости)
// Мы получили доступ к коллекции элементов через параметр
ЭлементыФормы = Форма.Элементы;
ЭлементыФормы.ГруппаСлужебнаяИнформация.Видимость = ЗначениеВидимости;
КонецПроцедуры
Преимущества данного подхода:
&НаСервере), при передаче ЭтаФорма в бесконтекстный метод передается только ссылка на структуру интерфейса, а не все данные реквизитов (объекта, табличных частей и т.д.).Проанализируем вопрос производительности при изменении видимости. Бытует мнение, что любое изменение интерфейса лучше делать на сервере. Давайте разберемся, так ли это.
Начиная с версии 8.3.7, платформа была значительно оптимизирована. Теперь изменение видимости простых элементов (полей ввода, кнопок) старается выполняться на клиенте без обращения к серверу. Однако есть исключения, когда серверный вызов неизбежен:
Выясним, какую стратегию выбора директив лучше использовать в повседневной разработке:
Во-первых, если задача заключается исключительно в визуальном изменении (скрыть одну кнопку или заблокировать поле), всегда отдавайте приоритет процедурам &НаКлиенте. Помните, что даже самый быстрый бесконтекстный вызов сервера — это сериализация данных в XML/JSON, сетевой пакет и обратная десериализация. Эти накладные расходы могут составлять 100-200 мс, что при частом использовании сделает интерфейс "дерганым".
Во-вторых, используйте &НаКлиентеНаСервереБезКонтекста только тогда, когда алгоритм действительно идентичен для обеих сторон. Например, расчет суммы по строке (Цена * Количество), который должен срабатывать и при вводе данных пользователем (на клиенте), и при программном заполнении документа (на сервере).
В-третьих, если вам все же нужно изменить видимость множества элементов, связанных сложной логикой, лучше сгруппировать их в одну процедуру. Передача формы как параметра в бесконтекстный метод &НаКлиентеНаСервереБезКонтекста в данном случае будет "золотой серединой" между удобством разработки и производительностью системы. Для интерактивного анализа и изменения параметров отображения элементов прямо во время работы системы можно использовать инструмент редактирования форм в режиме 1С:Предприятие.