О решении этой задачи рассказывает Ирина, разработчик 1С в нашей команде
ДеревоЗначений — один из самых коварных объектов. Оно идеально для визуализации иерархии, но при неправильном подходе превращает интерфейс в «тыкву». Главная проблема — сериализация: при каждом серверном вызове дерево гоняется целиком. Если в нем 100 000 строк, интерфейс «умрет». Разберем, как заставить его летать.
1. Ленивая загрузка (Lazy Loading) — Технически верно
Чтобы дерево открывалось мгновенно, подгружайте данные только при развертывании узла.
Шаг 1: Создаем маркер-пустышку (Сервер)
Если у узла есть дети, нужно «обмануть» платформу, чтобы она отрисовала «плюсик». Для этого добавляем одну пустую строку.
bsl
// На сервере при заполнении уровня (инициализация корня)
НоваяСтрока = КоллекцияВерхнегоУровня.Добавить();
НоваяСтрока.Наименование = "Группа товаров";
Если Выборка.ЭтоГруппа Тогда
// ПРАВИЛЬНО: Добавляем пустую подчиненную строку-маркер.
// Платформа увидит Количество() > 0 и нарисует "+" у узла.
НоваяСтрока.ПолучитьЭлементы().Добавить();
КонецЕсли;
Шаг 2: Обработка события (Клиент)
Используем штатное событие таблицы ПередРазворачиванием(Элемент, Строка, Отказ). Параметр Строка здесь — это идентификатор (Число).
bsl
&НаКлиенте
Процедура ДеревоПередРазворачиванием(Элемент, Строка, Отказ)
Узел = ДеревоДанных.НайтиПоИдентификатору(Строка);
Дочерние = Узел.ПолучитьЭлементы();
// ПРОВЕРКА: Если там только наша "пустышка" (одна строка без данных)
Если Дочерние.Количество() = 1 И Дочерние.Ссылка.Пустая() Тогда
ПодгрузитьДанныеНаСервере(Строка);
КонецЕсли;
КонецПроцедуры
Шаг 3: Дозагрузка данных (Сервер)
bsl
&НаСервере
Процедура ПодгрузитьДанныеНаСервере(ИдентификаторСтроки)
РодительскийУзел = ДеревоДанных.НайтиПоИдентификатору(ИдентификаторСтроки);
Коллекция = РодительскийУзел.ПолучитьЭлементы();
Коллекция.Очистить(); // Удаляем маркер-пустышку
Запрос = Новый Запрос("ВЫБРАТЬ Ссылка, Наименование, ЭтоГруппа ИЗ Справочник.Номенклатура ГДЕ Родитель = &Родитель");
Запрос.УстановитьПараметр("Родитель", РодительскийУзел.Ссылка);
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
НоваяСтрока = Коллекция.Добавить();
ЗаполнитьЗначенияСвойств(НоваяСтрока, Выборка);
Если Выборка.ЭтоГруппа Тогда // Снова ставим маркер для следующего уровня
НоваяСтрока.ПолучитьЭлементы().Добавить();
КонецЕсли;
КонецЦикла;
КонецПроцедуры
2. Рекурсия vs Итеративный обход (Стек)
Рекурсия — это красиво, но медленно и опасно (Stack Overflow). 1С тратит ресурсы на каждый вызов процедуры и управление стеком.
КАК НЕ НАДО, Если Деревозначений имеет большой объем(Рекурсия):
bsl
Процедура Обход(Строки)
Для Каждого Стр Из Строки Цикл
// Обработка...
Если Стр.Строки.Количество() > 0 Тогда // Лишний вызов метода в каждой итерации
Обход(Стр.Строки); // Рекурсивный вызов - ТОРМОЗИТ!
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Оптимальное (Итеративный обход через массив-стек):
Работает в 1.5–2 раза быстрее и никогда не упадет.
bsl
Процедура ОбходИтеративный(КорневыеСтроки)
Стек = Новый Массив;
Для Каждого Стр Из КорневыеСтроки Цикл Стек.Добавить(Стр); КонецЦикла;
Пока Стек.Количество() > 0 Цикл
ТекущаяСтрока = Стек[Стек.Количество() - 1];
Стек.Удалить(Стек.Количество() - 1);
// --- Полезная работа здесь ---
Подчиненные = ТекущаяСтрока.Строки;
Для Каждого Подч Из Подчиненные Цикл
Стек.Добавить(Подч);
КонецЦикла;
КонецЦикла;
КонецПроцедуры
3. Поиск: Забудьте про циклы
Метод НайтиСтроки(СтруктураОтбора, Истина) — это «черная магия» платформы на C++.
- Почему это оптимально: платформа обходит дерево напрямую в памяти, не создавая объекты «Строка» в интерпретаторе 1С.
- Когда НЕ использовать: если нужно искать 10 000 раз в цикле. В этом случае выгрузите дерево в ТаблицуЗначений, проиндексируйте её и ищите через ТЗ.Найти().
4. Оптимизация через СКД
Если дерево — это сложный отчет с итогами, не собирайте его запросами в цикле:
- Настройте СКД с иерархией группировок.
- Используйте ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений.
- СКД соберет дерево на уровне SQL и внутренних алгоритмов ядра, что в разы быстрее ручного заполнения.
Итоговый чек-лист производительности
|
Операция |
Ошибка (Тормоза) |
Решение (Скорость) |
|
Загрузка |
Всё дерево сразу |
Ленивая загрузка + "Пустышка" |
|
Обход |
Рекурсия |
Цикл Пока + Массив (Стек) |
|
Поиск |
Цикл Для Каждого |
НайтиСтроки(..., Истина) |
|
Оформление |
Сложные формулы И/ИЛИ |
Колонка-индекс цвета |
ДеревоЗначений — это визуальный объект, а не вычислительный. Считайте в таблицах или СКД, а пользователю отдавайте данные порциями через «Ленивую загрузку».
Вступайте в нашу телеграмм-группу Инфостарт
