Разработка и Конфигурация · 10 мин
Что значит «без контекста» в 1С
Что означает вызов «без контекста» в 1С:Предприятие, где применяется, чем отличается от контекстного вызова и как избежать типичных ошибок в коде.
Во встроенном языке 1С:Предприятие термин «без контекста» означает вызов процедуры или функции без привязки к конкретному объекту — форме, документу, записи регистра или элементу справочника. Такой вызов выполняется «в вакууме»: код не знает, из какой формы или объекта его запустили, и не имеет доступа к данным этого объекта напрямую.
Самое частое место, где разработчик встречает этот термин, — директивы компиляции в модулях форм: &НаКлиенте, &НаСервере, &НаСервереБезКонтекста, &НаКлиентеНаСервереБезКонтекста. Разработчик также сталкивается с понятием «без контекста» при работе с общими модулями, фоновыми заданиями и веб-сервисами, где контекст вызова отсутствует по определению.
Понимание разницы между контекстным и неконтекстным выполнением критично: попытка обратиться к реквизитам формы из процедуры «без контекста» приводит к ошибке компиляции или выполнения, а неправильный выбор директивы замедляет работу приложения из-за лишних серверных вызовов и передачи данных.
Что такое контекст в 1С и почему его может не быть
Контекст — это окружение, в котором выполняется код: набор доступных переменных, реквизитов, методов объекта, из которого вызвана процедура. Когда процедура находится в модуле формы и выполняется с контекстом, она «видит» реквизиты формы, элементы управления, объект данных (например, редактируемый документ) просто по имени.
Контекст отсутствует, когда код выполняется отдельно от объекта: в общем модуле, в фоновом задании, на сервере при вызове из клиентской процедуры без передачи формы. В этом случае у кода есть только те данные, которые ему явно передали через параметры.
Важно понимать, что «без контекста» — не синоним «на сервере». Это независимые характеристики: код может выполняться на сервере как с контекстом формы (директива &НаСервере в модуле формы), так и без него (&НаСервереБезКонтекста).
Директивы компиляции в модулях форм
В управляемых формах каждая процедура помечается директивой, определяющей, где и с каким контекстом она выполняется. Выбор директивы влияет на производительность и на то, какие данные доступны внутри процедуры.
| Директива | Где выполняется | Доступ к реквизитам формы |
|---|---|---|
&НаКлиенте | На клиенте | Есть (клиентский контекст формы) |
&НаСервере | На сервере | Есть (форма передаётся на сервер) |
&НаСервереБезКонтекста | На сервере | Нет, данные передаются параметрами |
&НаКлиентеНаСервереБезКонтекста | И там, и там | Нет, только параметры |
Директива &НаСервере удобна тем, что внутри процедуры доступны все реквизиты формы, включая основной реквизит с данными объекта. Но за это приходится платить: при каждом вызове вся форма сериализуется, передаётся на сервер, воссоздаётся там, а после выполнения результат передаётся обратно. При больших формах это ощутимые накладные расходы.
Директива &НаСервереБезКонтекста исключает передачу формы. Процедура получает только то, что указано в параметрах, — например, ссылку на документ или структуру с данными. Это быстрее и безопаснее с точки зрения нагрузки, но требует от разработчика продумать состав передаваемых данных.
Как выбрать директиву: практический маршрут
Выбор директивы определяется тем, какие данные нужны процедуре и как часто она вызывается. Универсального правила нет, но есть устойчивые рекомендации.
Как выбрать директиву
Частый антипаттерн — помечать все серверные процедуры формы директивой &НаСервере «для удобства». На формах с большими табличными частями это приводит к заметным задержкам при каждом серверном вызове, особенно на медленных каналах связи.
Общие модули и работа без контекста
Общие модули по своей природе работают без контекста формы: они не привязаны к конкретному объекту интерфейса. Флаги общего модуля («Сервер», «Клиент», «Вызов сервера», «Привилегированный режим») определяют, где компилируется и выполняется его код.
Флаг «Вызов сервера» у серверного общего модуля разрешает обращаться к нему с клиента. Без этого флага попытка вызвать серверный общий модуль из клиентской процедуры приведёт к ошибке. При этом все данные в такой модуль попадают только через параметры — это и есть классический вызов без контекста.
При передаче данных в серверный общий модуль учитывайте ограничение: между клиентом и сервером можно передавать только сериализуемые типы — примитивы, структуры, массивы, ссылки. Передать, например, объект ДанныеФормыСтруктура или таблицу значений напрямую нельзя; табличную часть обычно передают как массив структур или выгружают в значение через промежуточные механизмы.
&НаСервереБезКонтекста
Функция ПолучитьОстаток(Номенклатура, Склад)
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ ЕСТЬNULL(Остатки.КоличествоОстаток, 0) КАК Остаток
|ИЗ РегистрНакопления.ТоварыНаСкладах.Остатки(, Номенклатура = &Номенклатура И Склад = &Склад) КАК Остатки";
Запрос.УстановитьПараметр("Номенклатура", Номенклатура);
Запрос.УстановитьПараметр("Склад", Склад);
Выборка = Запрос.Выполнить().Выбрать();
Возврат ?(Выборка.Следующий(), Выборка.Остаток, 0);
КонецФункцииФоновые задания и внешние вызовы
Фоновые задания всегда выполняются без контекста: у них нет ни формы, ни сеанса пользователя в привычном смысле. В метод фонового задания передаются только параметры, указанные при вызове ФоновыеЗадания.Выполнить. Поэтому нельзя рассчитывать, что фоновое задание «увидит» открытую форму или её реквизиты.
Аналогично работают HTTP-сервисы, веб-сервисы и планы обмена: входящий вызов обрабатывается вне какого-либо пользовательского контекста. Все необходимые данные извлекаются из тела запроса, параметров или заголовков.
Если результат фонового задания нужно показать пользователю, данные возвращают через временное хранилище (ПоместитьВоВременноеХранилище), а клиентская процедура забирает их по адресу хранилища и отображает в форме.
Типичные ошибки и как их диагностировать
Большинство проблем с контекстом проявляется сразу — на этапе сохранения конфигурации или при первом вызове процедуры. Типичные симптомы и их причины сведены ниже.
Проверка результата после выбора директивы проста: модуль формы должен компилироваться без ошибок, процедура должна получать все нужные данные через параметры, а время отклика при вызове не должно расти по сравнению с прежним вариантом. Если процедура «не видит» нужную переменную — это верный признак, что она выполняется без контекста, а данные не переданы.
Как проверить результат
Нет ошибок «переменная не определена»
Ошибки на реквизиты формы в процедурах без контекста
Передаются только нужные ссылки и значения
Передаётся вся форма ради одного поля
Сериализуемый тип: структура, массив, ссылка, примитив
Попытка вернуть объект данных или элемент формы
Практические рекомендации
Старайтесь по умолчанию использовать &НаСервереБезКонтекста для серверных процедур формы, переходя на &НаСервере только когда реально нужна массовая работа с данными формы. Это дисциплинирует: состав входных и выходных данных становится явным, код проще тестировать и переносить в общие модули.
Вычислительную логику, не зависящую от интерфейса, выносите в общие модули. Тогда её можно вызывать из форм, фоновых заданий и сервисов без дублирования кода, а неконтекстная природа общих модулей перестаёт быть ограничением — она становится преимуществом.
Что важно запомнить
«Без контекста» — это выполнение кода без привязки к объекту: данные доступны только через параметры. Директива &НаСервереБезКонтекста ускоряет серверные вызовы, но требует явной передачи данных. Общие модули, фоновые задания и сервисы всегда работают без контекста формы.
Частые вопросы
Чем &НаСервере отличается от &НаСервереБезКонтекста?
Директива &НаСервере передаёт на сервер всю форму вместе с реквизитами и данными объекта, поэтому внутри процедуры они доступны напрямую. Директива &НаСервереБезКонтекста передаёт только параметры вызова — это быстрее, но реквизиты формы внутри недоступны.
Почему возникает ошибка «Переменная не определена» в процедуре формы?
Чаще всего процедура помечена директивой без контекста, а внутри неё идёт обращение к реквизиту формы по имени. Либо измените директиву на контекстную, либо передайте нужное значение параметром.
Можно ли изменить реквизит формы из процедуры без контекста?
Напрямую нет. Верните результат из функции и присвойте его реквизитам формы в вызывающей клиентской или контекстной серверной процедуре.
Какие типы данных можно передавать между клиентом и сервером?
Примитивные типы (строка, число, дата, булево), ссылки, структуры, массивы, соответствия и некоторые сериализуемые коллекции. Объекты данных (ДокументОбъект, ДанныеФормы) передавать нельзя — передавайте ссылку и получайте объект на сервере.
Почему фоновое задание не видит данные открытой формы?
Фоновое задание выполняется в отдельном сеансе на сервере и не имеет доступа к клиентским формам. Передайте нужные значения в параметрах при запуске, а результат верните через временное хранилище.
Когда оправдана директива &НаКлиентеНаСервереБезКонтекста?
Когда одна и та же вспомогательная логика (например, форматирование или расчёт без обращения к базе) нужна и на клиенте, и на сервере, а данных формы ей не требуется. Часто такой код лучше вынести в общий модуль.