При разработке сложных аналитических рабочих мест в управляемом приложении разработчики часто сталкиваются с ситуацией, когда серверный запрос выполняется быстро, однако возврат управления на клиент занимает несколько секунд. Разберем типичный сценарий: на сервере заполняется реквизит формы типа ДанныеФормыКоллекция (таблица из 5 500 строк и 30 колонок). От момента завершения серверного метода до передачи контроля в клиентский код проходит 5–6 секунд. Проанализируем физику этого процесса и рассмотрим эффективные варианты решения проблемы.
Выясним причину такой задержки. Основное узкое место здесь кроется не в сетевом канале как таковом, а в механизме работы управляемой формы:
&НаСервере платформа сравнивает состояние контекста до и после вызова. Если коллекция перезаполнена целиком, измененной считается каждая ячейка. При 5 500 строках и 30 колонках это 165 000 элементов данных. Сервер упаковывает их в подробный XML-пакет с описанием типов.ДанныеФормыЭлементКоллекции, а затем перерисовать таблицу в визуальном интерфейсе. Это блокирует пользовательский поток.Рассмотрим подробнее архитектурные подходы, позволяющие избежать передачи тяжелого контекста на клиент.
Вместо того чтобы держать в реквизитах формы все 5 500 строк, организуем постраничный вывод (например, порциями по 50–100 строк). Вся таблица формируется в неконтекстном вызове, кэшируется во временном хранилище, а в интерфейс передается только текущая страница.
Разберем реализацию этого механизма по шагам:
Посмотрим на пример кода серверных методов:
&НаСервереБезКонтекста
Функция СформироватьИСохранитьДанные(УникальныйИдентификаторФормы, АдресХранилища = "")
Таблица = ПолучитьПолнуюТаблицуДанных(); // Формирование исходной таблицы значений
Возврат ПоместитьВоВременноеХранилище(Таблица, УникальныйИдентификаторФормы);
КонецФункции
&НаСервере
Процедура ЗагрузитьСтраницуНаСервере(АдресХранилища, НомерСтраницы, РазмерСтраницы = 100)
ТаблицаИзХранилища = ПолучитьИзВременногоХранилища(АдресХранилища);
Если ТаблицаИзХранилища = Неопределено Тогда
Возврат;
КонецЕсли;
// Очищаем текущие данные формы
ТаблицаФормы.Очистить();
ИндексНачала = (НомерСтраницы - 1) * РазмерСтраницы;
ИндексКонца = Мин(ИндексНачала + РазмерСтраницы - 1, ТаблицаИзХранилища.Количество() - 1);
Для Индекс = ИндексНачала По ИндексКонца Цикл
ЗаполнитьЗначенияСвойств(ТаблицаФормы.Добавить(), ТаблицаИзХранилища[Индекс]);
КонецЦикла;
КонецПроцедуры
При таком подходе на клиент передается всего 100 строк, что занимает менее 0.1 секунды.
Главное достоинство объекта ДинамическийСписок заключается в том, что он по умолчанию считывает и передает на клиент только видимую область строк плюс небольшой запас для плавного скроллинга. Полная таблица из 5 500 строк не передается в клиентскую память целиком ни при каких условиях.
Если данные собираются сложным составным запросом, который нельзя уместить в один запрос динамического списка, хорошим решением является промежуточная запись результата в специализированный РегистрСведений с привязкой к сеансу или пользователю. После записи динамический список мгновенно отображает первые 30–40 строк, а прокрутка работает плавно и быстро.
Если список предназначен преимущественно для просмотра и выбора, проанализируем замену таблицы формы на ТабличныйДокумент. В тонком клиенте механизм табличного документа оптимизирован: отображение виртуализировано, и ячейки подгружаются по мере прокрутки экрана. Это избавляет систему от необходимости создавать тысячи тяжелых объектов типа ДанныеФормыЭлементКоллекции.
Если интерфейс требует наличия всех строк в едином списке, снизим объем XML-пакета за счет структуры данных:
СправочникСсылка, ДокументСсылка) требует передачи метаданных ссылок. Замените их на строковые представления (Строка) там, где не требуется открытие формы объекта по нажатию.