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