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

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

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

Что делать, если структура таблицы формируется динамически в режиме «1С:Предприятие» (всегда разные колонки), а сами данные запрашиваются напрямую из внешней СУБД MS SQL или PostgreSQL? Попытка загрузить все данные сразу в таблицу значений на форме приведет к критическому падению производительности и зависанию интерфейса. В этой статье мы подробно разберем, как обойти это ограничение и настроить плавный бесконечный скроллинг.

Почему стандартный Динамический список и Таблица значений не подходят «из коробки»

Прежде чем перейти к решениям, проанализируем причины ограничений стандартных механизмов 1С:

  1. Динамический список (ДС): Требует жесткого описания внешнего источника данных в конфигураторе. Если таблицы во внешней базе SQL создаются программно «на лету» и имеют произвольный набор колонок, ДС использовать напрямую не удастся.
  2. Прямая загрузка в ТаблицуЗначений (ТЗ): Если внешняя таблица содержит десятки или сотни тысяч строк, перегонять их все в ТЗ формы — крайне неоптимальная операция. Процесс трансляции данных из SQL в объектную модель 1С и последующая передача этого массива на клиент займет слишком много времени.
  3. Событие ПриАктивизацииСтроки: Прямая подгрузка данных внутри этого события вызывает «заикание» интерфейса, скачки курсора и бесконечное зацикливание вызовов, если не использовать специальные алгоритмы синхронизации.

Рассмотрим четыре эффективных архитектурных сценария решения этой задачи.

---

Решение 1. Оптимизированный скроллинг через «ПриАктивизацииСтроки» и обработчик ожидания

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

Разберем логику работы по шагам:

  1. При открытии формы мы загружаем только первую небольшую порцию данных (например, 50 строк) с помощью SQL-конструкций OFFSET и FETCH.
  2. Пользователь начинает прокручивать таблицу. В событии ПриАктивизацииСтроки мы проверяем индекс текущей строки.
  3. Если пользователь приблизился к концу доступного списка (например, находится на 45-й строке из 50), мы инициируем подгрузку следующей порции.
  4. Для предотвращения дублирования запросов во время выполнения серверного вызова мы используем переменную-флаг ЗагрузкаВПроцессе.
  5. Сам вызов сервера выполняется не напрямую, а через ПодключитьОбработчикОжидания с минимальным интервалом. Это позволяет форме завершить текущие интерфейсные операции и отрисовать фокус перед обращением к базе данных.

Посмотрим на пример реализации данного алгоритма в модуле управляемой формы:


&НаКлиенте
Перем ЗагрузкаВПроцессе; // Флаг для блокировки повторных запросов

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

&НаКлиенте
Процедура ПриОткрытии(Отказ)
    ЗагрузкаВПроцессе = Ложь;
КонецПроцедуры

&НаКлиенте
Процедура ТаблицаДанныхПриАктивизацииСтроки(Элемент)
    
    ТекущиеДанные = Элементы.ТаблицаДанных.ТекущиеДанные;
    Если ТекущиеДанные = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    // Определяем индекс текущей строки в коллекции
    ИндексТекущейСтроки = Объект.ТаблицаДанных.Индекс(ТекущиеДанные);
    ВсегоСтрокВТаблице = Объект.ТаблицаДанных.Количество();
    
    // Если пользователь подошел близко к концу (осталось менее 5 строк)
    Если (ИндексТекущейСтроки >= ВсегоСтрокВТаблице - 5) И Не ЗагрузкаВПроцессе Тогда
        ЗагрузкаВПроцессе = Истина;
        // Подключаем однократный обработчик с минимальной задержкой
        ПодключитьОбработчикОжидания("ПодключитьАсинхроннуюЗагрузку", 0.1, Истина);
    КонецЕсли;
    
КонецПроцедуры

&НаКлиенте
Процедура ПодключитьАсинхроннуюЗагрузку()
    
    Попытка
        ЗагрузитьСледующуюПорциюНаСервере();
    Исключение
        ЗагрузкаВПроцессе = Ложь;
        ВызватьИсключение;
    КонецПопытки;
    
    ЗагрузкаВПроцессе = Ложь;
    
КонецПроцедуры

&НаСервере
Процедура ЗагрузитьСледующуюПорциюНаСервере()
    
    // Выполняем быстрый SQL-запрос с пагинацией
    // Пример текста SQL-запроса: 
    // "SELECT * FROM TableName ORDER BY ID OFFSET " + ТекущееСмещение + " ROWS FETCH NEXT " + РазмерПорции + " ROWS ONLY"
    
    ТЗПорции = ПолучитьДанныеИзВнешнейБД(ТекущееСмещение, РазмерПорции);
    
    Если ТЗПорции.Количество() > 0 Тогда
        // Заполняем реквизит формы новыми строками
        Для Каждого СтрокаИсточника Из ТЗПорции Цикл
            НоваяСтрока = Объект.ТаблицаДанных.Добавить();
            ЗаполнитьЗначенияСвойств(НоваяСтрока, СтрокаИсточника);
        КонецЦикла;
        
        // Сдвигаем указатель смещения для следующего шага
        ТекущееСмещение = ТекущееСмещение + РазмерПорции;
    КонецЕсли;
    
КонецПроцедуры

---

Решение 2. Использование элемента «Поле HTML-документа»

Если стандартная таблица 1С при быстром скроллинге начинает подтормаживать из-за серверных вызовов отрисовки интерфейса, прогрессивным решением будет полный перенос рендеринга на сторону HTML/JS.

Этот метод основан на использовании элемента формы типа ПолеHTMLДокумента. Внутрь него загружается легковесный JS-код, который строит таблицу и самостоятельно отслеживает скроллинг страницы с помощью современного API браузеров — IntersectionObserver.

Разберем схему взаимодействия систем:

  1. В поле HTML загружается базовая разметка с пустой таблицей.
  2. На невидимый элемент внизу страницы (так называемый «сентинел» или маркер конца) вешается IntersectionObserver.
  3. Как только маркер попадает в зону видимости экрана (пользователь докрутил до конца), JavaScript генерирует внешнее событие для платформы 1С.
  4. 1С ловит событие в процедуре ДокументСформирован или ПриНажатии (в зависимости от версии платформы), быстро достает из SQL очередную пачку данных, преобразует её в формат JSON и отправляет обратно в HTML-поле.
  5. JavaScript мгновенно аппендит (дописывает) строки в объектную модель документа (DOM) без перезагрузки всей формы.

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

---

Решение 3. Опережающая фоновая загрузка данных (Pre-fetching)

Чтобы пользователь вообще не замечал задержек во время получения данных из внешней СУБД, можно применить стратегию упреждающего чтения. Вместо того чтобы запрашивать данные в момент достижения конца таблицы, мы делаем это заранее.

Проанализируем этот паттерн:

Для реализации фоновых вызовов без блокировки интерфейса можно использовать механизм ФоновыеЗадания 1С, результаты которых считываются периодическим обработчиком ожидания.

---

Решение 4. Программное перестроение схемы динамического списка

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

Для этого в момент открытия формы выполняется следующий алгоритм:

  1. С помощью метода формы ИзменитьРеквизиты() программно создается реквизит формы с типом ДинамическийСписок.
  2. Программно конструируется элемент формы типа Таблица и связывается с созданным динамическим списком.
  3. Текст запроса динамического списка формируется динамически на сервере. Чтобы связать его с внешней СУБД без описания таблиц в конфигураторе, используется промежуточное звено — создание временных таблиц в базе 1С через менеджер временных таблиц, либо предварительное наполнение локального временного регистра сведений, по которому строится запрос динамического списка.

Этот метод сложнее в реализации, но он незаменим, когда пользователю необходимы мощные интерактивные инструменты анализа данных, встроенные в платформу 1С.

Резюме

Реализация бесконечной прокрутки динамических данных в управляемых формах 1С вполне возможна и показывает отличные результаты производительности, если не загружать всю СУБД-таблицу целиком. Оптимальным выбором по соотношению «скорость разработки / надежность» является схема с обработчиком ожидания и флагом блокировки (Решение 1). Если же требуется максимальная кастомизация интерфейса и абсолютная плавность — обратите внимание на интеграцию с HTML/JS (Решение 2).

← На главную