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