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

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

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

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

Причина низкой производительности

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

Решение 1. Лайфхак со свойством «Начальное отображение дерева»

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

Давайте посмотрим на пример реализации этого метода:


&НаКлиенте
Процедура РазвернутьДеревоБыстро(Команда)
    
    // Вызываем серверный метод для обновления состояния данных, если это необходимо
    ДеревоНаСервере();
    
    // Переключаем свойство отображения дерева
    Если Элементы.ДеревоОстатков.НачальноеОтображениеДерева = НачальноеОтображениеДерева.РаскрыватьВерхнийУровень Тогда
        Элементы.ДеревоОстатков.НачальноеОтображениеДерева = НачальноеОтображениеДерева.РаскрыватьВсеУровни;
    Иначе
        Элементы.ДеревоОстатков.НачальноеОтображениеДерева = НачальноеОтображениеДерева.РаскрыватьВерхнийУровень;
    КонецЕсли;    
    
КонецПроцедуры

&НаСервере
Процедура ДеревоНаСервере()
    
    // Внимание! Избегайте без необходимости полной перезаписи реквизита:
    // тДерево = РеквизитФормыВЗначение("ДеревоОстатков");
    // ЗначениеВРеквизитФормы(тДерево, "ДеревоОстатков");
    // Это действие полностью перестраивает дерево и сводит на нет оптимизацию.
    
КонецПроцедуры

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

Решение 2. Ленивая загрузка (Lazy Loading) данных

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

Разберем по шагам, как это реализовать:

  1. При первоначальном заполнении дерева на сервере мы формируем только первый (верхний) уровень иерархии.
  2. Для каждого узла верхнего уровня, у которого заведомо есть подчиненные элементы, мы добавляем одну пустую строку-маркер («пустышку»). Платформа видит наличие дочерней строки и автоматически рисует знак «+» рядом с узлом.
  3. Для таблицы на форме определяем обработчик события ПередРазворачиванием.

Проанализируем пример кода для обработчика события разворачивания узла:


&НаКлиенте
Процедура ДеревоОстатковПередРазворачиванием(Элемент, Строка, Отказ)
    
    ТекущиеДанные = Элементы.ДеревоОстатков.ДанныеСтроки(Строка);
    
    // Проверяем, загружены ли данные или там все еще находится маркер-пустышка
    Если ТребуетсяЗагрузкаПодчиненных(Строка) Тогда
        
        // Отказываемся от стандартного разворачивания на время получения данных
        Отказ = Истина;
        
        // Загружаем подчиненные строки с сервера для конкретного узла
        ЗагрузитьПодчиненныеСтрокиНаСервере(Строка);
        
        // Теперь разворачиваем узел программно
        Элементы.ДеревоОстатков.Развернуть(Строка, Ложь);
        
    КонецЕсли;
    
КонецПроцедуры

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

Решение 3. Оптимизация отображения типов данных

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

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

  1. В колонках дерева, предназначенных для просмотра, храните не сами ссылки, а их текстовые представления (тип Строка).
  2. Если ссылка необходима для дальнейшей работы (например, для открытия карточки объекта), добавьте на форму скрытую колонку с типом ссылки, отключив для нее видимость, а пользователю показывайте только текстовое поле.

Решение 4. Использование динамического списка с группировкой

Если дерево значений используется только для вывода информации и не предполагает сложного интерактивного редактирования множества полей «на лету», лучшей альтернативой будет использование Динамического списка с настроенной группировкой колонок.

Динамический список изначально спроектирован для работы с большими массивами данных. Он считывает информацию из базы данных порциями (постранично), а механизмы разворачивания группировок в нем оптимизированы на уровне платформы «1С:Предприятие» и работают практически мгновенно.

← На главную