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