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