Как быстро свернуть и развернуть большое дерево значений на форме 1С?

Программист 1С v8.3 (Управляемые формы) 1С:ERP Управление предприятием Управленческий учет Промышленность, строительство и АПК
← На главную

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

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

Суть проблемы: почему 1С "виснет" при работе с деревом?

Давайте проанализируем ситуацию, описанную в теме. Имеется дерево на управляемой форме. На первом уровне иерархии находится около 1600 строк. Общее количество строк с учетом всех вложенных уровней (рекурсия, комплектующие изделий) может достигать 500 000 записей. Задача состоит в том, чтобы развернуть все узлы дерева программно.

Автор использовал стандартный подход:


// Пример кода, вызывающего проблему
Для Каждого СтрокаДерева Из ДеревоРезультат.ПолучитьЭлементы() Цикл
    Элементы.ДеревоРезультат.Развернуть(СтрокаДерева.ПолучитьИдентификатор(), Истина);
КонецЦикла;

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

Почему это происходит? Основная нагрузка ложится не на серверную выборку данных (которая, по словам автора, проходит за 15-20 секунд), а на клиентскую отрисовку. Каждый развернутый узел — это создание новых элементов управления в памяти клиента, расчет их геометрии, применение условного оформления и получение представлений для ссылочных полей.

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

Способ 1. Оптимизация типов данных (Строки вместо Ссылок)

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

При массовом разворачивании узлов (тысячи элементов одновременно) система начинает генерировать огромное количество запросов к кешу или базе данных для получения текстового наименования и иконки каждой ссылки. Это "узкое горлышко" рендеринга.

Решение: Подготовим данные заранее.

  1. В запросе, формирующем дерево, сразу получаем текстовые представления (Наименования, Артикулы).
  2. В само Дерево Значений на форме добавляем колонки строкового типа, а не ссылочного.
  3. Ссылку можно хранить в скрытой колонке или использовать идентификатор (GUID) для связи с базой данных при необходимости редактирования.

Рассмотрим пример того, как это меняет логику заполнения:


// Вместо прямой выборки ссылки
// ВЫБРАТЬ Номенклатура ...

// Используем получение представления
ВЫБРАТЬ
    ПРЕДСТАВЛЕНИЕ(Номенклатура) Как НоменклатураТекст,
    Номенклатура.Артикул Как Артикул,
    Номенклатура.Ссылка Как СсылкаДляПоиска // Скрытая колонка
...

Использование простых типов (строк и чисел) значительно облегчает работу графической подсистемы 1С, так как ей не нужно тратить время на "разыменование" ссылок.

Способ 2. Управление видимостью элемента формы

Существует технический прием, который иногда позволяет ускорить массовые операции с элементами управления. Платформа 1С пытается перерисовывать элемент после каждого изменения его состояния. Если мы скроем элемент с экрана на время выполнения цикла развертывания, мы можем сэкономить ресурсы на промежуточных перерисовках.

Попробуем применить следующий алгоритм:


// Отключаем видимость перед началом операции
Элементы.ДеревоРезультат.Видимость = Ложь;

// Выполняем тяжелую операцию развертывания
Для Каждого СтрокаДерева Из ДеревоРезультат.ПолучитьЭлементы() Цикл
    Элементы.ДеревоРезультат.Развернуть(СтрокаДерева.ПолучитьИдентификатор(), Истина);
КонецЦикла;

// Включаем видимость обратно
Элементы.ДеревоРезультат.Видимость = Истина;

Однако стоит учитывать, что при объеме данных в 500 000 строк этот метод может лишь незначительно сократить время, но не решит проблему зависания полностью, так как объем данных для отрисовки остается критическим для браузера (тонкого клиента).

Способ 3. Ленивая загрузка (Lazy Loading)

Самый профессиональный подход при работе с большими деревьями в интерактивном режиме — не загружать и не разворачивать всё сразу. Пользователь физически не может охватить взглядом 500 000 строк. Ему нужен контекст.

Принцип "ленивой загрузки" заключается в следующем:

  1. При открытии формы мы загружаем в дерево только верхний уровень иерархии.
  2. Для каждого узла проверяем, есть ли у него потенциальные потомки. Если есть — добавляем одну фиктивную (пустую) подстроку. Это заставит платформу нарисовать "плюсик" (крестик) разворота.
  3. Подписываемся на событие ПередРазворачиванием элемента формы.
  4. В момент нажатия на "плюс" программно удаляем фиктивную строку, делаем запрос к базе данных за реальными потомками именно этого узла и заполняем их.

Этот метод делает открытие формы мгновенным. Да, он не решает задачу "развернуть всё одной кнопкой" (так как это противоречит самой идеологии оптимизации UI), но он решает задачу комфортной работы пользователя с данными.

Примерная логика обработчика:


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

Способ 4. Смена парадигмы: Табличный документ вместо Дерева

Если задача стоит жестко: "Нужно вывести полный отчет на 500 000 строк с иерархией и возможностью быстро сворачивать/разворачивать уровни", то Дерево значений на форме — это неправильный инструмент. Для решения подобных задач оптимизации вывода больших объемов данных отлично подойдет метод ускорения выполнения отчетов в 1С.

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

Преимущества Табличного документа в данном кейсе:

Для реализации сворачивания/разворачивания в табличном документе достаточно корректно использовать метод НачатьГруппуСтрок() при выводе областей макета.


// Пример вывода группировки в табличный документ
ТабДок.НачатьГруппуСтрок("ГруппаКомплектующие", Истина); // Истина - группа свернута по умолчанию? 
// ... вывод детальных записей ...
ТабДок.ЗакончитьГруппуСтрок();

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

Выводы и рекомендации

Проанализировав обсуждение и технические возможности платформы 1С, мы можем сделать следующие выводы для решения задачи с деревом на 500 000 строк:

  1. Откажитесь от идеи "Развернуть всё" в дереве формы. Это технически неэффективно и неудобно для пользователя. Ни один человек не способен работать с таким списком без фильтров и поиска.
  2. Используйте Табличный документ. Если целью является просмотр полного состава изделия (BOM) со всей вложенностью, реализуйте это через отчет (на СКД или программный вывод в макет). Там механизмы группировок работают оптимизировано.
  3. Оптимизируйте Дерево, если оно необходимо. Если без дерева формы не обойтись (например, нужно отмечать галочками строки для обработки):
    • Замените ссылочные поля на строковые.
    • Отключите условное оформление на момент заполнения.
    • Используйте динамическую (ленивую) загрузку данных по мере раскрытия веток.
  4. Ограничьте выборку. Если пользователь не установил отборы, не загружайте все 500 000 записей. Выведите предупреждение или ограничьте вывод первыми 1000 записями (как предлагалось в обсуждении), чтобы избежать "падения" клиента 1С.
← На главную