Почему возникает неявный вызов сервера при обращении к реквизиту формы на клиенте?

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

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

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

Постановка проблемы: клиентский код с серверным акцентом

Рассмотрим ситуацию, с которой столкнулся разработчик. Имеется общий модуль с установленными флагами "Клиент (управляемое приложение)" и "Клиент (обычное приложение)". В этом модуле есть экспортная процедура, которая не содержит явных вызовов серверных методов. Однако при её вызове из формы наблюдается задержка около 0,2 секунды, а замер производительности показывает активность на стороне сервера.

Код, вызывающий подозрение, выглядит крайне просто и безобидно:


// Примерный код в модуле формы или общем модуле
Если ЭтаФорма.Объект.Ссылка.Пустая() Тогда
    // Какая-то логика
КонецЕсли;

Возникают резонные вопросы:

  1. Почему контекст формы "уезжает" на сервер при сугубо клиентской проверке?
  2. Почему первый вызов длится дольше (0,2 сек), а последующие проходят быстрее?
  3. Как правильно выполнять подобные проверки, чтобы интерфейс оставался отзывчивым?

Анализ причины №1: Природа ДанныхФормы и Кэширование метаданных

Чтобы понять происходящее, нам нужно вспомнить, с чем именно мы работаем на клиенте. В управляемой форме мы взаимодействуем не с самими прикладными объектами (например, СправочникОбъект), а с их проекцией — типом ДанныеФормыСтруктура (или ДанныеФормыКоллекция).

Когда мы пишем ЭтаФорма.Объект.Ссылка, мы обращаемся к коллекции значений, имитирующей структуру объекта. Платформа должна вернуть нам типизированное значение. Если это первое обращение к данному типу метаданных (например, к конкретному справочнику) в рамках текущего сеанса или контекста формы, платформа может инициировать неявный вызов сервера.

Зачем это нужно платформе?

Платформе необходимо загрузить на клиент кэш метаданных — описание структуры объекта, правил его представления и типов данных. Именно это объясняет тот факт, что первый вызов занимает 0,2 секунды (происходит подгрузка и кэширование), а последующие выполняются за 0,02 секунды (данные берутся из локального кэша).

Анализ причины №2: Правило точки и неявные вызовы

В среде 1С существует так называемое "правило точки" для реквизитов формы. Оно гласит: получение свойств ссылочного типа через точку от реквизита формы (если этих данных нет в кэше представления) вызывает обращение к серверу.

Давайте разберем цепочку вызова Объект.Ссылка.Пустая():

  1. Мы обращаемся к Объект (это ДанныеФормыСтруктура).
  2. Мы обращаемся к свойству .Ссылка. На этом этапе платформа должна извлечь значение ссылки. Хотя само значение ссылки обычно хранится в форме, для корректной работы с ним как с объектом типа СправочникСсылка платформе может потребоваться синхронизация.
  3. Мы вызываем метод .Пустая(). Сам по себе этот метод клиентский и "легкий". Но он выполняется уже над результатом предыдущего шага.

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

Анализ причины №3: Маршалинг и передача параметров

В ходе обсуждения проблемы выяснилась интересная деталь. Если передавать параметры в процедуру общего модуля с ключевым словом Знач, время выполнения сокращается.


// Было (медленнее)
Процедура МояПроцедура(Данные) Экспорт

// Стало (быстрее)
Процедура МояПроцедура(Знач Данные) Экспорт

Почему это влияет на производительность?

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

Даже если модуль клиентский, механизм передачи параметров (маршалинг) требует ресурсов на подготовку контекста. Использование Знач сигнализирует платформе, что изменения внутри процедуры не нужно возвращать "наружу". Это упрощает механизм передачи, позволяя избежать лишнего копирования памяти или создания сложных прокси-объектов, что и дает выигрыш во времени (в примере автора — сокращение с 0,2 до 0,1 секунды).

Решения и оптимизация кода

Теперь, когда мы понимаем механику, давайте рассмотрим способы оптимизации проверки "на пустоту" или "на новизну" объекта, которые не будут дергать сервер.

Способ 1. Использование свойства Ключ

У основного реквизита управляемой формы (который обычно называется Объект) есть системное свойство расширения формы — Ключ. Это свойство содержит ссылку на редактируемый объект базы данных.

Вместо:


// Может вызвать неявное обращение к серверу
Если Объект.Ссылка.Пустая() Тогда ...

Используйте:


// Работает стабильнее и быстрее
Если Объект.Ключ.Пустая() Тогда ...

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

Способ 2. Метод ЭтоНовый()

Если ваша цель — проверить, записан ли объект в базу данных (то есть является ли он новым), то использование проверки ссылки на пустоту — это не самый семантически верный путь. Для этого в расширении управляемой формы существует специальный метод.

Используйте:


// Оптимальный вариант для формы
Если ЭтаФорма.ЭтоНовый() Тогда ...
// или в некоторых контекстах просто
Если ЭтоНовый() Тогда ...

Метод ЭтоНовый() работает исключительно с состоянием формы на клиенте и не требует обращения к данным объекта или вызовов сервера.

Способ 3. Передача параметров по Значению

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


// Правильное объявление процедуры для обработки данных формы "только для чтения"
Процедура ВыполнитьРасчет(Знач ТекущиеДанные) Экспорт
    // Логика расчета
КонецПроцедуры

Подведем итоги

Мы выяснили, что "мистика" с вызовом сервера при клиентском коде имеет вполне техническое объяснение. Давайте закрепим основные выводы:

  1. Первое обращение к свойствам ссылочного типа (.Ссылка) может инициировать загрузку кэша метаданных с сервера. Это разовая операция для сеанса.
  2. Работа с ДанныеФормыСтруктура требует аккуратности. Избегайте лишних обращений через точку к свойствам, которых может не быть в кэше представления.
  3. Для проверки, записан ли объект, используйте методы расширения формы ЭтоНовый() или свойство Ключ, вместо обращения к Объект.Ссылка.
  4. Используйте передачу параметров через Знач в процедурах, где не требуется модификация переданных данных, чтобы снизить накладные расходы на маршалинг.

Применяя эти простые правила, мы можем сделать интерфейс наших решений на платформе 1С более отзывчивым и быстрым.

← На главную