В процессе разработки в среде 1С:Предприятие 8.3 программисты часто сталкиваются с проблемой производительности при работе с большими табличными частями. Типичная ситуация: в документе (например, «Коммерческое предложение» или «Заказ покупателя») содержится более сотни строк, и при изменении цены или количества программа начинает «задумываться» на несколько секунд. Рассмотрим, почему это происходит и как правильно оптимизировать код пересчета.
Разберем стандартную ошибку начинающего разработчика. Часто логика расчета помещается в цикл, который обходит всю табличную часть при любом изменении. Проанализируем пример кода, который вызывает задержки:
&НаКлиенте
Процедура ТоварыЦенаПриИзменении(Элемент)
Для Каждого СтрокаТаблицыТовары Из Объект.Товары Цикл
СтрокаТаблицыТовары.ЦенаСНДС = СтрокаТаблицыТовары.Цена +
СтрокаТаблицыТовары.Цена * РасчетСтавки(СтрокаТаблицыТовары.СтавкаНДС) / 100;
КонецЦикла;
КонецПроцедуры
Проблема здесь заключается в том, что при изменении цены всего в одной строке, система вынуждена заново вычислять значения для всех 100 или 500 строк. Ситуация усугубляется, если внутри цикла вызывается функция РасчетСтавки, которая может выполнять серверный вызов. Каждый серверный вызов — это передача данных по сети, что критически замедляет работу интерфейса.
Если пользователь редактирует конкретную ячейку, нам не нужно пересчитывать весь документ. Достаточно получить данные той строки, в которой находится курсор. Для этого в управляемых формах используется свойство ТекущиеДанные элемента формы (таблицы).
Выясним, как изменить код для мгновенного пересчета. Вместо цикла Для Каждого мы обратимся напрямую к активной строке:
&НаКлиенте
Процедура ТоварыЦенаПриИзменении(Элемент)
// Получаем строку, которую пользователь редактирует в данный момент
ТекСтрока = Элементы.Товары.ТекущиеДанные;
Если ТекСтрока <> Неопределено Тогда
// Выполняем расчет только для этой строки
СтавкаЧислом = РасчетСтавки(ТекСтрока.СтавкаНДС);
ТекСтрока.ЦенаСНДС = ТекСтрока.Цена + (ТекСтрока.Цена * СтавкаЧислом / 100);
КонецЕсли;
КонецПроцедуры
Этот подход позволяет сократить время выполнения операции в десятки раз, так как 1С обрабатывает только один объект в оперативной памяти клиента.
Часто возникает ситуация, когда нам все же нужно пересчитать все строки (например, при изменении флага «Цена включает НДС» в шапке документа). Чтобы не дублировать код, проанализируем методику создания универсальной процедуры. Программисты рекомендуют использовать директиву &НаКлиентеНаСервереБезКонтекста для таких расчетов.
Рассмотрим пошагово, как это реализовать:
ПриИзменении конкретной колонки.Пример реализации такой структуры:
&НаКлиентеНаСервереБезКонтекста
Процедура РассчитатьСтрокуНДС(СтрокаТЧ)
// Выносим формулу в отдельное место для удобства обслуживания
// Добавляем округление, чтобы избежать проблем с копейками
Ставка = ?(СтрокаТЧ.СтавкаНДС = ПредопределенноеЗначение("Перечисление.СтавкиНДС.НДС20"), 20, 0);
СтрокаТЧ.ЦенаСНДС = Окр(СтрокаТЧ.Цена + (СтрокаТЧ.Цена * Ставка / 100), 2);
КонецПроцедуры
&НаКлиенте
Процедура ТоварыЦенаПриИзменении(Элемент)
РассчитатьСтрокуНДС(Элементы.Товары.ТекущиеДанные);
КонецПроцедуры
&НаКлиенте
Процедура ЦенаВключаетНДСПриИзменении(Элемент)
// Здесь цикл оправдан, так как меняется глобальный признак
Для Каждого Стр Из Объект.Товары Цикл
РассчитатьСтрокуНДС(Стр);
КонецЦикла;
КонецПроцедуры
Разберем дополнительные нюансы, которые помогут сделать ваш код еще более профессиональным:
1. Округление (Функция Окр): В финансовых расчетах 1С крайне важно всегда использовать округление. Если этого не делать, при сложении ЦенаСНДС по всем строкам может возникнуть погрешность в несколько копеек из-за скрытых знаков после запятой, что приведет к ошибкам в бухгалтерском учете.
2. Контекстные вызовы: Старайтесь избегать использования функции РасчетСтавки, если она требует обращения к серверу (директива &НаСервере). Посмотрите, можно ли получить значения ставок НДС заранее при открытии формы и сохранить их в структуру на клиенте, чтобы расчет в строках происходил мгновенно без «пинга» до сервера.
3. Видимость колонок: Как было замечено в обсуждении, программное изменение видимости (Элементы.Колонка.Видимость = Ложь) — это ресурсозатратная операция. Если вы меняете видимость в цикле или очень часто, форма будет «моргать». Лучше использовать свойство ТолькоПросмотр или менять видимость один раз при изменении состояния документа, а не для каждой строки отдельно.
Если в вашей табличной части тысячи строк, даже цикл &НаКлиенте может подтормаживать. В этом случае проанализируем стратегию переноса расчетов на сервер. Вместо перебора строк на клиенте, можно передать объект на сервер, выполнить расчет с использованием временных таблиц или объектов ТаблицаЗначений, и вернуть результат. На сервере массовые операции с коллекциями выполняются быстрее за счет оптимизации работы с памятью в платформе 1С.
Подведем итог: для быстрой работы интерфейса всегда используйте ТекущиеДанные для обработки действий пользователя в конкретной строке. Массовый пересчет (цикл) оставляйте только для тех случаев, когда меняются реквизиты шапки, влияющие на весь документ целиком. Соблюдение этих правил сделает работу пользователей в программе комфортной и эффективной.