Как правильно работать с произвольными типами данных на форме и оптимизировать клиент-серверное взаимодействие в 1С?

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

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

Основная проблема: Неочевидная синхронизация данных формы

Мы выясним причину, по которой изменения в данных формы, особенно когда речь идет о реквизитах с типом Произвольный или объектах, не напрямую связанных с формой, могут не передаваться на сервер или обратно на клиент. Платформа 1С:Предприятие реализует ряд оптимизаций для минимизации трафика между клиентом и сервером.

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

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

Контекстные и внеконтекстные вызовы: Ключ к пониманию

Для эффективной работы с клиент-серверным взаимодействием нам необходимо четко понимать разницу между контекстными и внеконтекстными серверными вызовами.

Контекстные вызовы

При контекстной передаче управления на сервер (например, при вызове процедуры, помеченной директивой &НаСервере без дополнительных условий), помимо явно указанных параметров процедуры/функции, на сервер автоматически передаются все данные формы, которые были изменены на клиенте с момента предыдущего контекстного серверного вызова. На сервере выполняются дополнительные действия по инициализации методов формы и серверной копии данных формы. Этот процесс может увеличивать общее время обработки, поскольку требует больше ресурсов и трафика.

Внеконтекстные вызовы

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

Важно отметить, что в некоторых клиентских обработчиках событий форм (например, ПередЗаписью, ПослеЗаписи, ПередЗакрытием, ПриЗакрытии) не допускается вызов контекстных серверных процедур или действий, которые могут привести к неявному серверному вызову. Это еще раз подчеркивает важность правильного выбора типа вызова.

Работа с Произвольными типами данных на форме

Когда мы работаем с реквизитами формы, мы должны учитывать их предназначение и ограничения по типам данных.

  1. Типы данных реквизитов формы: Реквизиты формы предназначены для хранения данных, с которыми работает форма. В данных формы могут храниться данные только тех типов системы "1С:Предприятие", для которых указана возможность XDTO-сериализации.
  2. Запрещенные типы: Запрещено присваивать реквизитам формы значения типа Массив и Соответствие. Эти типы не могут быть корректно сериализованы для передачи между клиентом и сервером в качестве прямых значений реквизитов формы.
  3. Тип "Произвольный": Если в качестве типа реквизита формы выбран тип "Произвольный" и в качестве значения реквизита выбрано мутабельное значение (например, объект, структура), то для корректной передачи данных между клиентом и сервером может потребоваться предпринять дополнительные действия. Платформа не всегда отслеживает глубокие изменения внутри такого объекта.
  4. Проблемы с сохранением и представлением: Значение типа "Произвольный" может не сохраняться автоматически в настройках формы. Для ссылочных типов мы можем заменить "Произвольный" на "Любая ссылка", и значения будут подставляться корректно. Программно создать реквизит формы произвольного типа, в который нужно передать структуру с сервера, может быть проблематично, так как структура не имеет визуального представления по умолчанию. Мы рекомендуем использовать типы, которые могут быть представлены визуально или обернуть произвольные данные в объекты, которые могут быть сериализованы.

Почему платформа оптимизирует передачу данных?

Давайте выясним, почему платформа 1С:Предприятие так активно оптимизирует клиент-серверное взаимодействие. Основная цель — минимизировать объем передаваемых данных между клиентом и сервером, что особенно критично при работе через низкоскоростные каналы связи.

  1. Передача только изменений: Платформа передает только изменения контекста, а не весь контекст целиком. Это достигается за счет отслеживания изменений в реквизитах формы.
  2. Частичное представление данных: При открытии формы на клиент передается только часть данных, которая видна пользователю в данный момент. На клиенте имеется лишь частичное представление данных формы, которое при необходимости подгружается с сервера.
  3. Серверные вызовы при операциях: При записи и закрытии формы происходит серверный вызов, аналогичный контекстному, при котором изменения данных формы после последней синхронизации отправляются на сервер. После обработки события "После записи на сервере", форма передается на клиент. При этом передаются измененные реквизиты, элементы и параметры формы, необходимые для отображения.
  4. Оптимизация больших объемов: Платформа 1С самостоятельно оптимизирует объем передаваемых данных при работе с большими объемами данных, таких как реквизиты формы с табличными документами или коллекции элементов (ДанныеФормыКоллекция, ДанныеФормыСтруктураСКоллекцией, ДанныеФормыДерево). В этих случаях затраты ресурсов сервера на инициализацию контекста формы оправдываются существенным снижением трафика и числа вызовов сервера.

Общие рекомендации по оптимизации и написанию кода

Для создания высокопроизводительных и надежных решений в 1С мы должны придерживаться следующих рекомендаций:

  1. Легкость формы: Форма должна быть "легкой" и работать максимально быстро. Избегайте размещения на форме избыточного количества элементов и данных, которые не используются постоянно.
  2. Минимизация вызовов и трафика: Оптимизация клиент-серверного взаимодействия заключается в уменьшении количества вызовов сервера и объема передаваемых данных (трафика). На некоторых видах соединения количество вызовов очень сильно влияет на производительность, так как каждый вызов может занимать значительное время, независимо от объема данных.
  3. Серверная подготовка данных: При открытии формы все подготовительные действия с табличными частями желательно производить на сервере. Если выполнять аналогичные действия на клиенте, это может привести к передаче всех данных табличной части на клиент, даже если они не требуются для отображения, что увеличит трафик.
  4. Разумная оптимизация: Не стоит бездумно гнаться за оптимизацией, так как это может сделать код нечитаемым и усложнить поддержку. Важно найти "золотую середину" между оптимизацией и хорошо читаемым, поддерживаемым кодом.
  5. Поиск "узких мест": "Узкие места" производительности могут скрываться не только в модулях форм, но и в других местах, например, в неоптимально написанных запросах. Всегда анализируйте производительность комплексно.
  6. Использование хороших имен: Всегда используйте хорошие, осмысленные имена переменных и реквизитов. Это значительно улучшает читаемость и поддерживаемость кода, снижая вероятность ошибок, связанных с неправильным пониманием назначения данных.

Пример работы с произвольными данными и синхронизацией

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

Неправильный подход (изменения могут не синхронизироваться автоматически):

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


&НаКлиенте
Процедура ИзменитьПроизвольныйРеквизитНаКлиенте()
    // Предположим, МоиНастройки - это Структура, хранящаяся в реквизите формы
    // с типом "Произвольный".
    // Если МоиНастройки.КлючСуществует("МоеПоле"), то
    //     МоиНастройки.МоеПоле = "НовоеЗначение";
    // Иначе
    //     МоиНастройки.Вставить("МоеПоле", "НовоеЗначение");
    // КонецЕсли;
    //
    // В этом случае платформа может не "увидеть" изменение МоиНастройки как
    // изменение реквизита формы, требующее передачи на сервер.
    // Если дальше мы вызовем контекстную серверную процедуру,
    // МоиНастройки могут быть переданы на сервер в старом состоянии.
КонецПроцедуры

Правильный подход (принудительная синхронизация произвольных данных):

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


&НаКлиенте
Процедура ИзменитьПроизвольныйРеквизитНаКлиентеИСинхронизировать()
    // Предположим, МоиНастройки - это Структура, хранящаяся в реквизите формы
    // с типом "Произвольный".

    // Создадим временную копию или получим текущее значение
    // Важно: если МоиНастройки - это уже объект, его можно изменить напрямую,
    // но для гарантии синхронизации, мы должны явно указать, что реквизит формы изменился.
    ПеременнаяСоНастройками = МоиНастройки;

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

    // Очень важный шаг: переприсваиваем реквизит формы самому себе.
    // Это явно сообщает платформе, что реквизит формы МоиНастройки изменился
    // и его нужно синхронизировать при следующем контекстном вызове сервера.
    МоиНастройки = ПеременнаяСоНастройками;

    // Теперь вызовем серверную процедуру, чтобы передать изменения.
    // Если нам нужно передать только МоиНастройки, можно использовать внеконтекстный вызов.
    // Если же нам нужен весь контекст формы, используем контекстный.
    ПередатьНастройкиНаСервер(МоиНастройки);
КонецПроцедуры

&НаСервереБезКонтекста
Процедура ПередатьНастройкиНаСервер(Настройки)
    // Здесь мы получили измененные настройки с клиента.
    // Можем сохранить их куда-либо, например, в хранилище общих настроек.
    // Например:
    // ОбщиеНастройки.Сохранить("МоиНастройкиПользователя", Настройки);
КонецПроцедуры

Этот пример демонстрирует, что для произвольных типов данных, которые являются мутабельными объектами, простое изменение их внутренних свойств может быть недостаточно для автоматической синхронизации. Мы должны явно "пометить" реквизит формы как измененный, чтобы платформа включила его в передачу данных при контекстном вызове сервера или передать его явно как параметр внеконтекстной процедуры.

Мы надеемся, что этот подробный разбор поможет вам лучше понять механизмы работы форм и клиент-серверного взаимодействия в 1С:Предприятии, а также позволит создавать более эффективные и предсказуемые решения.

← К списку