#std487

Минимизация количества серверных вызовов и трафика

1.1.

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

Общее количество серверных вызовов складывается из:

  • обращений, которые выполняет сама платформа;
  • вызовов из клиентского кода конфигурации.

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

Исключение

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

1.2.

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

Запуск клиентского приложения

2.1.

Код обработчиков ПередНачаломРаботыСистемы и ПриНачалеРаботыСистемы в простом сценарии не должен обращаться к серверу.

Если без сервера не обойтись:

  • не вызывайте серверные процедуры и функции напрямую из модуля приложения, модуля управляемого приложения и модуля внешнего соединения;
  • передавайте на клиент все стартовые параметры за один серверный вызов.

Если одни и те же параметры старта нужны в разных местах клиентского кода, используйте #std724: модуль с повторным использованием возвращаемых значений. Тогда сервер вызывается один раз, а затем результат кешируется на клиенте.

Пример

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

Если в конфигурации используется БСП, применяйте ее программный интерфейс:

  • размещайте серверный код запуска в процедурах ПриДобавленииПараметровРаботыКлиентаПриЗапуске и/или ПриДобавленииПараметровРаботыКлиента модуля ОбщегоНазначенияПереопределяемый;
  • на клиенте вызывайте ПараметрыРаботыКлиентаПриЗапуске или ПараметрыРаботыКлиента модуля СтандартныеПодсистемыКлиент, их результат кешируется после первого вызова.
См. также

Периодические серверные вызовы

3.1.

Когда нужно периодически передавать данные с клиента на сервер или проверять состояние сервера, объединяйте проверки в один вызов и выбирайте период как можно реже, обычно не чаще одного раза в 20 минут.

Типовые сценарии:

  • отправка данных о производительности и параметрах клиента;
  • контроль динамического обновления конфигурации или прав пользователя;
  • контроль завершения работы пользователей;
  • проверка актуальности курсов валют;
  • проверка напоминаний пользователя.

По возможности используйте уведомления клиентам через МенеджерУведомленийКлиента, а не периодический опрос сервера с клиента.

3.2.

Если используется БСП, реализуйте периодическое взаимодействие через ее программный интерфейс.

3.2.1.

Для длительных операций ожидайте результат через ДлительныеОперацииКлиент.ОжидатьЗавершение.

3.2.2.

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

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

3.2.3.

Для периодической проверки состояния сервера и отправки оповещений клиентам:

  • описывайте серверные оповещения в ПриДобавленииСерверныхОповещений модуля ОбщегоНазначенияПереопределяемый;
  • реализуйте отправку из регламентного задания ОтправкаСерверныхОповещенийКлиентам в ПриОтправкеСерверногоОповещения нужного общего модуля;
  • реализуйте обработку на клиенте в ПриПолученииСерверногоОповещения этого же модуля.
3.2.4.

Для периодической отправки данных с клиента на сервер:

  • добавляйте клиентские данные в ПередПериодическойОтправкойДанныхКлиентаНаСервер модуля ОбщегоНазначенияКлиентПереопределяемый;
  • обрабатывайте данные на сервере в ПриПериодическомПолученииДанныхКлиентаНаСервере модуля ОбщегоНазначенияПереопределяемый;
  • обрабатывайте ответ сервера на клиенте в ПослеПериодическогоПолученияДанныхКлиентаНаСервере модуля ОбщегоНазначенияКлиентПереопределяемый.

Открытие управляемой формы

4.1.

Если форма открывается из кода, выполняйте это за один вызов ОткрытьФорму. (Для платформы 8.2 и более ранних версий также ОткрытьФормуМодально).

Параметры передавайте через параметр Параметры этого метода.

4.2.

При открытии формы не вызывайте сервер из клиентских обработчиков ПриОткрытии и ПриПовторномОткрытии. Если нужны серверные данные, заполните реквизиты формы заранее в ПриСозданииНаСервере.

Пример

Фоновое задание длительного расчета запускайте в ПриСозданииНаСервере, а проверку готовности стартуйте в ПриОткрытии. См. #std642: Длительные операции на сервере.

Неправильно

НастройкаПроксиСервера = СерверныйМодуль.НастройкаПроксиСервера();
ПараметрыОткрытия = Новый Структура("Настройка", НастройкаПроксиСервера);
ОткрытьФорму("ОбщаяФорма.ПараметрыПроксиСервера", ПараметрыОткрытия);

Правильно

ОткрытьФорму("ОбщаяФорма.ПараметрыПроксиСервера");

Значение константы получайте в ПриСозданииНаСервере формы ПараметрыПроксиСервера.

Также при открытии формы не вызывайте серверные функции с повторным использованием возвращаемых значений: при первом вызове кеш еще не прогрет и возникает лишний вызов сервера.

4.3.

Не подключайте несколько разных обработчиков ожидания (ПодключитьОбработчикОжидания) для проверки готовности фоновых заданий одной формы. Это создает избыточные серверные вызовы.

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

Если используется БСП, запускайте длительные операции через ДлительныеОперации и ДлительныеОперацииКлиент. В них уже реализовано объединение обработчиков и оптимальные интервалы ожидания.

Выполнение локальной команды управляемой формы

5.1.

Локальная команда формы должна приводить максимум к одному серверному вызову.

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

Пример

При выборе номенклатуры нужно запретить выбор групп. Для этого не вызывайте серверную функцию проверки группы, а добавьте признак ЭтоГруппа в таблицу, связанную с полем списка.

ТекущаяСтрока = Элемент.ТекущиеДанные;
Если ТекущаяСтрока.ЭтоГруппа Тогда
    Сообщение = Новый СообщениеПользователю;
    Сообщение.Текст = НСтр("ru = 'Выбор группы запрещен.'");
    Сообщение.Сообщить();
    Возврат;
КонецЕсли;

Если команда запускает бизнес-логику, доступную только на сервере, выполняйте ее целиком за один серверный вызов.

Выбор из справочника

5.2.

В общем случае выбор из справочника должен вызывать только один серверный вызов из кода: вызов, который возникает при ОткрытьФорму (или ОткрытьФормуМодально).

6.3.

Если после выбора нужна бизнес-логика, выполняемая только на сервере, допустим один дополнительный серверный вызов.

Выполнение глобальной команды

6.1.

Глобальная команда должна приводить максимум к одному серверному вызову из кода. Если команда открывает форму, этот вызов должен происходить при ОткрытьФорму (или ОткрытьФормуМодально).

Выполнение команды формирования отчета

7.1.

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

В частности, при открытии формы отчета не обращайтесь к серверу в ПриОткрытии и ПриПовторномОткрытии.

Неправильно

&НаКлиенте
Процедура ПриОткрытии(Отказ)
    ВывестиОтчет();
КонецПроцедуры

&НаСервере
Процедура ВывестиОтчет()
    // Код формирования отчета
КонецПроцедуры

Правильно

  • открывать форму отчета с параметром СформироватьПриОткрытии = Истина;
  • или устанавливать СформироватьПриОткрытии = Истина в ПриСозданииНаСервере.

Выполнение подбора элементов

8.1.

При подборе элементов между формой объекта и формой подбора передается список выбранных элементов. Объем таких данных может быть большим.

Не передавайте потенциально большой массив напрямую параметром формы подбора. Если массив хранится как ДанныеФормыКоллекция, форма может передать его неполностью, и платформа выполнит дополнительное дочитывание данных с сервера.

8.2.

Для оптимизации передачи данных между формами используйте временное хранилище, а чтение и запись выполняйте на сервере.

Ниже пример подбора товаров в документ РасходТовара:

  • при открытии формы подбора: первый вызов на сервер для помещения данных во временное хранилище, второй вызов для открытия формы;
  • при закрытии формы подбора: первый вызов для записи результата в хранилище, второй вызов для загрузки результата в форму документа.
// Форма документа
&НаКлиенте
Процедура ОбработчикКомандыПодбора()
    АдресТоваровВХранилище = ПоместитьТоварыВХранилище();

    ПараметрыПодбора = Новый Структура;
    ПараметрыПодбора.Вставить("АдресТоваровДокумента", АдресТоваровВХранилище);
    ПараметрыПодбора.Вставить("ВидЦен", Объект.ВидЦен);
    ПараметрыПодбора.Вставить("Склад", Объект.Склад);

    ОткрытьФорму("Документ.РасходТовара.Форма.ФормаПодбора", ПараметрыПодбора, Элементы.Товары);
КонецПроцедуры

&НаСервере
Функция ПоместитьТоварыВХранилище()
    Возврат ПоместитьВоВременноеХранилище(
        Объект.Товары.Выгрузить(, "Товар,Цена,Количество"),
        УникальныйИдентификатор
    );
КонецФункции
// Форма подбора
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка) Экспорт
    АдресТоваровДокумента = Параметры.АдресТоваровДокумента;
    Объект.Товары.Загрузить(ПолучитьИзВременногоХранилища(АдресТоваровДокумента));
КонецПроцедуры
// Закрытие формы подбора
&НаКлиенте
Процедура ОКВыполнить()
    АдресТоваровВоВременномХранилище = ЗаписатьПодборВХранилище();
    ОповеститьОВыборе(АдресТоваровВоВременномХранилище);
КонецПроцедуры

&НаСервере
Функция ЗаписатьПодборВХранилище()
    Возврат ПоместитьВоВременноеХранилище(Товары.Выгрузить(), АдресТоваровДокумента);
КонецФункции
// Форма документа: обработка результата подбора
&НаКлиенте
Процедура ПриОбработкеПодобранныхТоваров(Элемент, АдресТоваровВХранилище, СтандартнаяОбработка) Экспорт
    Если АдресТоваровВХранилище = Неопределено Тогда
        Возврат;
    КонецЕсли;

    ПолучитьТоварыИзХранилища(АдресТоваровВХранилище);
КонецПроцедуры

&НаСервере
Процедура ПолучитьТоварыИзХранилища(АдресТоваровВХранилище)
    ПодобранныеТовары = ПолучитьИзВременногоХранилища(АдресТоваровВХранилище);
    Объект.Товары.Загрузить(ПодобранныеТовары);
    УдалитьИзВременногоХранилища(АдресТоваровДокумента); // освобождаем память
КонецПроцедуры
8.3.

При работе с временным хранилищем используйте один из двух вариантов:

  • хранение на время жизни формы (по УникальныйИдентификатор) с последующей очисткой;
  • предварительная инициализация и переиспользование одного адреса.

Если этого не делать, при многократном выполнении действия (например, повторный подбор) растет расход оперативной памяти.

&НаСервере
Процедура ПриСозданииНаСервере(Отказ)
    АдресТоваров = ПоместитьВоВременноеХранилище(Неопределено, УникальныйИдентификатор);
КонецПроцедуры

&НаСервере
Функция ТоварыВоВременномХранилище()
    Возврат ПоместитьВоВременноеХранилище(Товары.Выгрузить(), АдресТоваров);
КонецФункции

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

&НаСервере
Процедура ПолучитьТоварыИзХранилища(АдресТоваровВХранилище)
    ПодобранныеТовары = ПолучитьИзВременногоХранилища(АдресТоваровВХранилище);
    Объект.Товары.Загрузить(ПодобранныеТовары);
КонецПроцедуры

Запись формы

9.

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

Данные передавайте на клиент через ПараметрыЗаписи или реквизиты формы.

Неправильно

&НаКлиенте
Процедура ПослеЗаписи()
    УправлениеФормой();
КонецПроцедуры

&НаСервере
Процедура УправлениеФормой()
    ...
КонецПроцедуры

Правильно

Вызывайте УправлениеФормой в ПослеЗаписиНаСервере. Перед вызовом проверяйте, будет ли форма закрыта: если форма закрывается, управлять ею не нужно.

Неявные серверные вызовы

10.

Учитывайте клиентские методы и свойства, которые могут вызывать сервер:

  • ПолучитьИзВременногоХранилища, УдалитьИзВременногоХранилища;
  • свойства поля формы, например Заголовок, Доступность, Подсказка, ТолькоПросмотр;
  • ПолучитьФункциональнуюОпциюИнтерфейса, ПолучитьФункциональнуюОпциюФормы;
  • другие методы и свойства из синтаксис-помощника с аналогичным поведением.

Избегайте многократных вызовов таких методов из клиентского кода. Объединяйте их в один серверный вызов: используйте одно временное хранилище или переносите логику в одну серверную процедуру.

Также не вызывайте серверные функции с повторным использованием возвращаемых значений в сценариях, где первый вызов приходится на открытие формы или другой критичный путь. Используйте подходы из п. 4.2 для модулей форм и из п. 2.1 для прочего клиентского кода.

Передача данных между клиентом и сервером

11.

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

Неправильно

&НаКлиенте
Процедура ПриАктивизацииСтрокиСпискаКонтрагентов()
    ОбновитьПанельКонтактнойИнформацииСервер();
КонецПроцедуры

&НаСервере
Процедура ОбновитьПанельКонтактнойИнформацииСервер()
    КонтактнаяИнформацияПанель.ОбновитьДанныеПанели(ЭтотОбъект, ТекущийКонтрагент);
КонецПроцедуры

Правильно

&НаКлиенте
Процедура ПриАктивизацииСтрокиСпискаКонтрагентов()
    ОбновитьПанельКонтактнойИнформации();
КонецПроцедуры

&НаКлиенте
Процедура ОбновитьПанельКонтактнойИнформации()
    ДанныеПанели = ДанныеПанелиКонтактнойИнформации(ТекущийКонтрагент);
    КонтактнаяИнформацияПанельКлиент.ЗаполнитьДанныеПанелиКИ(ЭтотОбъект, ДанныеПанели);
КонецПроцедуры

&НаСервереБезКонтекста
Функция ДанныеПанелиКонтактнойИнформации(Контрагент)
    Возврат КонтактнаяИнформацияПанель.ДанныеПанелиКонтактнойИнформации(Контрагент);
КонецФункции
12.

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

В параметрах серверных процедур и функций, вызываемых с клиента, рекомендуется использовать префикс Знач. Это снижает объем обратной передачи параметров, особенно для сложных типов (Структура, Массив и т.д.).

Правило относится к:

  • экспортным процедурам и функциям общих модулей с признаком Вызов сервера;
  • процедурам модулей форм и команд с директивами &НаСервере, &НаСервереБезКонтекста;
  • процедурам без директив (неявное &НаСервере).

Пример

&НаКлиенте
Процедура ОбработкаКоманды(ПараметрКоманды, ПараметрыВыполненияКоманды)
    НовоеОбсуждение = НовоеОбсуждение(ПараметрКоманды);
    ...
КонецПроцедуры

Неправильно

&НаСервере
Функция НовоеОбсуждение(ПользовательСсылка)
    ...
    Возврат ПолучитьНавигационнуюСсылку(Обсуждение.Идентификатор);
КонецФункции

Правильно

&НаСервере
Функция НовоеОбсуждение(Знач ПользовательСсылка)
    ...
    Возврат ПолучитьНавигационнуюСсылку(Обсуждение.Идентификатор);
КонецФункции
См. также
Источник

https://its.1c.ru/db/v8std#content:487