Как оптимизировать обращение к серверу с формы при расчете данных в табличной части?

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

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

Проблема контекстных вызовов

В исходном коде автора используется процедура с директивой &НаСервере. Давайте выясним причину, почему это замедляет работу. Когда мы вызываем контекстную серверную процедуру, платформа сериализует всю форму. Это означает, что все данные объекта (реквизиты заголовка, все строки всех табличных частей, состояние элементов управления) упаковываются в пакет, передаются на сервер, там восстанавливаются, обрабатываются, а затем весь этот объем данных возвращается обратно на клиент.

Если в вашей табличной части 1000 строк, то при изменении количества в одной строке вы будете каждый раз «гонять» по сети данные всех 1000 строк. Рассмотрим решение: замена директивы на &НаСервереБезКонтекста.

Проанализируем исправленный код:


&НаСервереБезКонтекста
Функция ПолучитьСкидку(СсылкаНаСкидку)
    Возврат СсылкаНаСкидку.ЗначениеСкидки;
КонецФункции

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

Оптимизация обращения к базе данных (Проблема «точки»)

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

Рассмотрим более профессиональный подход с использованием функций Библиотеки стандартных подсистем (БСП). Разберем пример кода:


&НаСервереБезКонтекста
Функция ПолучитьСкидку(Скидка)
    // Используем БСП для получения только одного конкретного поля
    Возврат ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Скидка, "ЗначениеСкидки");
КонецФункции

Функция ОбщегоНазначения.ЗначениеРеквизитаОбъекта выполняет оптимальный SQL-запрос SELECT, выбирая из таблицы базы данных только поле ЗначениеСкидки. Это снижает нагрузку на СУБД и ускоряет выполнение серверного вызова.

Проверка корректности текущих данных

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

Проанализируем ситуацию: если пользователь стоит на пустой строке или удалил строку, Элементы.Товары.ТекущиеДанные вернет Неопределено. Правильный алгоритм действий выглядит так:


&НаКлиенте
Процедура ТоварыКоличествоПриИзменении(Элемент)
    
    ТекДанные = Элементы.Товары.ТекущиеДанные;
    
    // Сначала проверяем наличие данных
    Если ТекДанные = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    // Проверяем, заполнена ли ссылка на скидку, чтобы не ходить на сервер зря
    Если ТекДанные.Скидка.Пустая() Тогда
        ПроцентСкидки = 0;
    Иначе
        ПроцентСкидки = ПолучитьСкидку(ТекДанные.Скидка);
    КонецЕсли;
    
    // Выполняем расчеты
    РассчитатьСтрокуТЧ(ТекДанные, ПроцентСкидки);
    
КонецПроцедуры

Метод денормализации (хранение данных в ТЧ)

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

Разберем по шагам:

  1. Добавим в табличную часть «Товары» реквизит ПроцентСкидки (тип: Число).
  2. Будем получать значение процента с сервера только один раз — когда пользователь выбирает или меняет саму скидку в колонке «Скидка».
  3. При изменении количества или цены будем брать процент из этой же строки ТЧ на клиенте.

Посмотрим, как изменится код обработки события цены:


&НаКлиенте
Процедура ТоварыЦенаПриИзменении(Элемент)
    
    ТекДанные = Элементы.Товары.ТекущиеДанные;
    Если ТекДанные = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    // Нам НЕ НУЖЕН серверный вызов здесь! 
    // Процент уже лежит в строке табличной части.
    СкидкаПроцент = ТекДанные.ПроцентСкидки;
    
    ТекДанные.Сумма = ТекДанные.Количество * ТекДанные.Цена;
    ТекДанные.СуммаСкидки = ТекДанные.Сумма * СкидкаПроцент / 100;
    ТекДанные.Всего = ТекДанные.Сумма - ТекДанные.СуммаСкидки;  
    
КонецПроцедуры

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

Кэширование данных на клиенте

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

Рассмотрим пример реализации кэша в модуле формы:


&НаКлиенте
Перем КэшСкидок; // Переменная будет жить, пока открыта форма

&НаКлиенте
Функция ПолучитьПроцентСкидкиСКэшированием(СсылкаСкидка)
    
    Если КэшСкидок = Неопределено Тогда
        КэшСкидок = Новый Соответствие;
    КонецЕсли;
    
    Процент = КэшСкидок.Получить(СсылкаСкидка);
    
    Если Процент = Неопределено Тогда
        // Если в кэше нет - идем на сервер
        Процент = ПолучитьСкидкуНаСервере(СсылкаСкидка);
        КэшСкидок.Вставить(СсылкаСкидка, Процент);
    КонецЕсли;
    
    Возврат Процент;
    
КонецФункции

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

Групповые операции и пакетная обработка

Представим ситуацию, когда пользователь нажимает кнопку «Пересчитать все скидки в документе». Типичная ошибка — запустить цикл по строкам и в каждой строке вызывать &НаСервереБезКонтекста. Это породит сотни маленьких запросов, что крайне неэффективно.

Разберем правильный алгоритм групповой обработки:

  1. На клиенте соберем все уникальные ссылки на скидки из всех строк в Массив.
  2. Передадим этот массив на сервер одним вызовом.
  3. На сервере одним запросом получим таблицу соответствий «Ссылка — Значение».
  4. Вернем эту таблицу (или ФиксированноеСоответствие) на клиент.
  5. На клиенте в цикле обновим все строки, используя полученные данные.

Важный момент: всегда старайтесь минимизировать количество «прыжков» между клиентом и сервером. Один тяжелый запрос всегда лучше, чем сто легких.

Подводя итог, мы проанализировали несколько уровней оптимизации: от простого изменения директив компиляции до изменения архитектуры данных в табличной части. Использование &НаСервереБезКонтекста, отказ от избыточных блоков Попытка, внедрение кэширования и денормализации — это стандарт профессиональной разработки на 1С 8.3, который обеспечивает комфортную работу пользователей.

← На главную