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