Как оптимизировать открытие и программную настройку обычной формы в 1С?

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

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

Почему обычную форму нельзя полностью передать на сервер

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

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

Скрытые причины зависания при открытии формы

Рассмотрим, что именно создает критическую нагрузку на слабую клиентскую станцию:

  1. Неявные сетевые вызовы в циклах. Если во время обхода элементов формы код проверяет права или обращается через точку к реквизитам ссылочных типов (например, Ссылка.Организация.Префикс), толстый клиент выполняет синхронные вызовы к серверу базы данных. Десятки таких обращений в цикле приводят к долгому открытию.
  2. Событие ПриОткрытии вместо ПередОткрытием. В обработчике ПриОткрытии визуальные дескрипторы окон уже созданы в графической подсистеме операционной системы. Каждое изменение свойств видимости и доступности провоцирует каскадный пересчет геометрии окна и повторную перерисовку. В событии ПередОткрытием окно еще не визуализировано, поэтому первичное применение параметров проходит быстрее.
  3. Наложение неиндексированных отборов. Установка программных отборов для табличных полей без индексов вызывает первичное сканирование таблиц базы данных при инициализации формы.

Способ 1. Пакетный расчет параметров на сервере за один вызов

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

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


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

А в общем модуле с признаком выполнения Сервер и установленным флагом Вызов сервера разместим логику вычисления интерфейса:


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

Способ 2. Однократное кэширование правил при запуске системы

Если варианты запуска и ограничения доступа для пользователя статичны и не зависят от реквизитов открываемого объекта, рассчитывать эти данные при каждом открытии формы избыточно. Разберем по шагам, как ускорить этот процесс:

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

Способ 3. Оптимизация интерфейсной части и элементов управления

Проанализируем визуальную структуру формы. Перебор 30–50 отдельных элементов управления для изменения их свойств создает ощутимую нагрузку на подсистему GDI на слабой машине. Для решения этой проблемы применим группировку:

  1. Использование страниц панели. Объединим зависимые элементы на страницах элемента управления Панель. Скрытие или отображение одной страницы панели (ЭлементыФормы.ОсновнаяПанель.Страницы.Служебные.Видимость = Ложь;) выполняется платформой за одну атомарную операцию и не вызывает лавинообразных перерисовок отдельных полей.
  2. Свойство НастройкаОтбора. При управлении доступностью и составом отборов в списках используйте обращение к свойству НастройкаОтбора табличного поля до считывания основных данных, чтобы минимизировать число запросов к СУБД.

Альтернативные архитектурные решения

Если оптимизация клиентского кода не дает желаемого эффекта на предельно слабом оборудовании, рассмотрим альтернативные варианты:

  1. Создание нескольких статических форм. Вместо одной универсальной перегруженной формы, которая трансформируется на лету, создадим в конфигураторе 2–3 специализированные формы для конкретных ролей. Нужная форма открывается через вызов ПолучитьФорму() с передачей имени конкретной формы объекта.
  2. Использование терминального доступа (RDS / RDP). Толстый клиент обычного приложения активно расходует ресурсы клиентского процессора и памяти. Перенос выполнения клиента на терминальный сервер полностью снимает аппаратные ограничения локальных машин пользователей.
← На главную