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