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