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

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

В процессе оптимизации клиент-серверного взаимодействия в управляемом приложении 1С разработчики часто стремятся перевести серверные вызовы в директиву &НаСервереБезКонтекста. При этом возникает типичная задача: как передать таблицу с клиента на сервер, выполнить над ней сложные манипуляции (например, через объект ТаблицаЗначений) и вернуть обновленные строки обратно в реквизит формы.

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

Анализ исходного кода и типичные ошибки

Рассмотрим код, предложенный в вопросе:


&НаКлиенте
Процедура Пр1(Команда)
    КопироватьДанныеФормы(Пр2(Реквизит1), Реквизит1);
КонецПроцедуры

&НаСервереБезКонтекста
Функция Пр2(Знач Реквизит1)
    ТабЗнч = ДанныеФормыВЗначение(Реквизит1, Тип("ТаблицаЗначений"));
    // Выполняются действия над таблицей значений
    ЗначениеВДанныеФормы(ТабЗнч, Реквизит1);
    Возврат Реквизит1;
КонецФункции

Разберем детально, что здесь происходит и какие ошибки или неоптимальности допущены:

  1. Работа глобальных методов без контекста: Методы ДанныеФормыВЗначение() и ЗначениеВДанныеФормы() являются глобальными процедурами/функциями платформы 1С. В отличие от РеквизитФормыВЗначение() и ЗначениеВРеквизитФормы(), они не требуют контекста формы и штатно выполняются во внеконтекстных вызовах и общих модулях. Поэтому вызов этих методов в процедуре &НаСервереБезКонтекста абсолютно корректен.
  2. Избыточное использование передачи по значению (Знач): Ключевое слово Знач заставляет платформу создать изолированную копию коллекции. Из-за этого изменения внутри функции не передаются обратно автоматически, и разработчику приходится возвращать значение функцией и вручную вызывать КопироватьДанныеФормы() на клиенте.
  3. Трафик сериализации: При вызове &НаСервереБезКонтекста с передачей коллекции ДанныеФормыКоллекция вся таблица целиком сериализуется в XML/JSON и отправляется на сервер, а затем целиком возвращается обратно. Если таблица содержит много строк, такой вызов может оказаться значительно «тяжелее» и медленнее обычного контекстного вызова.

Вариант 1. Оптимизация передачи по ссылке без контекста

Если мы хотим оставить внеконтекстный вызов, но избавиться от лишнего дублирования и ручного копирования данных на клиенте, уберем ключевое слово Знач и заменим функцию на процедуру. В этом случае платформа автоматически организует двустороннюю передачу данных:


&НаКлиенте
Процедура ОбработатьТаблицу(Команда)
    ОбработатьТаблицуНаСервереБезКонтекста(Реквизит1);
КонецПроцедуры

&НаСервереБезКонтекста
Процедура ОбработатьТаблицуНаСервереБезКонтекста(Реквизит1)
    // Преобразуем ДанныеФормыКоллекция в ТаблицуЗначений
    ТабЗнч = ДанныеФормыВЗначение(Реквизит1, Тип("ТаблицаЗначений"));
    
    // Выполняем действия над ТаблицейЗначений (сортировка, расчеты, итоги)
    // ...
    
    // Загружаем обновленные данные обратно в параметр
    ЗначениеВДанныеФормы(ТабЗнч, Реквизит1);
КонецПроцедуры

Посмотрим, почему этот вариант работает чище: платформа передает коллекцию на сервер, метод ЗначениеВДанныеФормы() перезаполняет переданную коллекцию Реквизит1, и после завершения вызова изменения автоматически отображаются в реквизите формы на клиенте без дополнительных вызовов КопироватьДанныеФормы().

Вариант 2. Использование контекстного вызова формы

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


&НаКлиенте
Процедура ОбработатьТаблицу(Команда)
    ОбработатьТаблицуНаСервере();
КонецПроцедуры

&НаСервере
Процедура ОбработатьТаблицуНаСервере()
    ТабЗнч = РеквизитФормыВЗначение("Реквизит1");
    
    // Обработка данных таблицы значений
    // ...
    
    ЗначениеВРеквизитФормы(ТабЗнч, "Реквизит1");
КонецПроцедуры

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

Вариант 3. Передача только измененных данных или использование временного хранилища

Если таблица содержит сотни или тысячи строк, передавать всю коллекцию между клиентом и сервером крайне неэффективно. В таких сценариях рекомендуются следующие архитектурные подходы:

  1. Передача массива структур: Передавать на сервер только идентификаторы (или ключевые поля) выбранных строк и необходимые параметры расчета, вместо всей таблицы целиком.
  2. Использование временного хранилища: Если таблица формируется на сервере в результате сложного запроса или отчета, поместим готовый объект ТаблицаЗначений во временное хранилище с помощью метода ПоместитьВоВременноеХранилище(), передав на клиент только строковый адрес, а отображение организуем порционно или по мере необходимости.
← На главную