Глобальный, модульный и серверный контекст в 1С 8.3 на примерах

· 9 мин

Содержание

Контекст в 1С — это набор переменных, процедур, свойств и объектов, которые доступны коду в данной точке программы. Если имя есть в контексте, его можно вызвать без указания модуля. Если нет — платформа выдаст Переменная не определена или Процедура или функция с указанным именем не определена.

В 8.3 у слова два измерения. Первое — область видимости: глобальный, модульный и локальный контекст. Второе — где выполняется код: на клиенте или на сервере, с данными формы или без них. Почти все «непонятные» ошибки начинающих разработчиков связаны со вторым.

Контекст простыми словами: что видит строка кода

Представьте, что каждая строка кода стоит в комнате. В комнате лежат её локальные переменные. Дверь ведёт в коридор — это модуль с его переменными и процедурами. Коридор выходит в общий холл — глобальный контекст, доступный всем. Строка видит всё, что лежит в её комнате, в коридоре и в холле. В чужие комнаты она не заглядывает.

Добавьте к этому второе здание — сервер. Клиент и сервер работают в разных процессах, часто на разных компьютерах. Переменная, которая живёт на клиенте, на сервере не существует, и наоборот. Чтобы передать что-то между зданиями, нужен вызов сервера и параметры.

Пользователи встречают слово «контекст» и в другом смысле: контекстное меню (правая кнопка мыши) и контекстная подсказка в Конфигураторе (Ctrl+Пробел). Подсказка показывает ровно то, что доступно в текущем контексте, — удобный способ проверить, видит ли код нужное имя.

Три уровня видимости в 1С: глобальный, модульный, локальный

УровеньЧто входитГде объявляетсяСколько живёт
ГлобальныйСвойства и методы платформы (Сообщить, ТекущаяДата, Метаданные), менеджеры (Справочники, Документы — на сервере), общие модули, экспортные методы глобальных общих модулейПлатформа и конфигурацияВесь сеанс
МодульныйПеременные модуля (Перем ... ; в начале), все процедуры и функции модуля, свойства объекта-владельцаМодуль объекта, формы, менеджера, общий модульПока жив объект-владелец
ЛокальныйПараметры процедуры и переменные внутри неёВнутри процедуры или функцииОдин вызов

Глобальный контекст

Сюда входит всё, что можно вызвать из любого места без префикса. Методы платформы, перечисленные в синтакс-помощнике в разделе «Глобальный контекст». Имена общих модулей: ОбщегоНазначения.ЗначениеРеквизитаОбъекта(...). А если у общего модуля стоит флажок «Глобальный», его экспортные методы вызываются вообще без имени модуля.

К глобальному клиентскому контексту относятся и экспортные переменные модуля управляемого приложения. Их видит любой клиентский код конфигурации.

Глобальные общие модули компилируются при старте сеанса. Чем их больше, тем дольше запуск. Для новых модулей флажок «Глобальный» обычно не ставят: вызов ИмяМодуля.Метод() читается понятнее и не тормозит старт.

Модульный контекст

Каждый модуль формирует свой контекст. В модуле объекта это реквизиты и табличные части объекта, а также ЭтотОбъект. В модуле формы — реквизиты формы, элементы (Элементы.Поле), основной реквизит Объект и сама форма через ЭтаФорма или ЭтотОбъект.

Переменные модуля объявляются в самом начале, до процедур:

&НаКлиенте
Перем СчетчикНажатий; // живёт, пока открыта форма

&НаКлиенте
Процедура КнопкаНажатие(Команда)
    СчетчикНажатий = ?(СчетчикНажатий = Неопределено, 1, СчетчикНажатий + 1);
КонецПроцедуры

Локальный контекст

Параметры и переменные внутри процедуры. Они создаются при входе и исчезают при выходе. Переменную внутри процедуры можно не объявлять через Перем — она появляется при первом присваивании.

Как контексты взаимодействуют и кто кого видит

Когда платформа встречает имя, она ищет его снизу вверх: сначала в локальном контексте процедуры, затем в модуле, затем в глобальном контексте. Поэтому локальная переменная с тем же именем, что и переменная модуля, перекрывает её. Это частый источник тихих ошибок: значение «пропадает», хотя код выглядит верным.

Чтобы чужой модуль увидел процедуру, нужно ключевое слово Экспорт:

  • 📦 экспортная процедура общего модуля доступна как ИмяМодуля.Процедура();
  • 📄 экспортная процедура модуля объекта — как метод объекта: ДокументОбъект.ЗаполнитьПоОснованию();
  • 🗂 экспортная переменная модуля объекта — как свойство объекта;
  • 🪟 экспортная процедура модуля формы — как метод формы, полученной через ПолучитьФорму() или ОткрытьФорму().

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

Контекст выполнения: клиент, сервер и директивы компиляции

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

ДирективаГде выполняетсяДанные формыЧто доступно
&НаКлиентеНа клиентеЕстьЭлементы формы, клиентские методы, диалоги, работа с файлами клиента
&НаСервереНа сервереЕсть, передаются с клиентаРеквизиты формы, РеквизитФормыВЗначение, запросы, менеджеры объектов
&НаСервереБезКонтекстаНа сервереНетТолько параметры, запросы, менеджеры, общие серверные модули
&НаКлиентеНаСервереБезКонтекстаТам, откуда вызванаНетТолько то, что есть и на клиенте, и на сервере

Для общих модулей директивы заменяют флажки в свойствах модуля: «Клиент (управляемое приложение)», «Сервер», «Вызов сервера», «Внешнее соединение», «Привилегированный». Серверный модуль без флажка «Вызов сервера» с клиента напрямую не вызвать — нужен посредник с этим флажком.

Внутри одного модуля можно разделять код инструкциями препроцессора #Если Сервер Тогда ... #КонецЕсли. Это не то же самое, что директивы компиляции: инструкция отсекает фрагмент текста при компиляции под конкретную сторону, а директива назначает место выполнения целой процедуре.

Что можно вызывать из чего

  • ✅ клиент → сервер (с контекстом и без) — это и есть вызов сервера;
  • ✅ сервер с контекстом → сервер без контекста;
  • ❌ сервер без контекста → процедура &НаСервере той же формы: у неё нет формы, с которой работать;
  • ❌ сервер → клиент: обратного вызова нет, результат возвращают через возвращаемое значение.

Вызов сервера с контекстом и без: что уходит по сети

При вызове &НаСервере платформа упаковывает данные формы, отправляет их на сервер, восстанавливает форму там, выполняет процедуру и возвращает изменённые данные обратно. Если на форме табличная часть на 5 000 строк, она поедет туда и обратно ради одной строки кода.

&НаСервереБезКонтекста передаёт только параметры. Поэтому совет практиков простой: если серверной процедуре не нужны реквизиты формы, делайте её без контекста и передавайте нужное параметрами.

Медленно — вся форма уходит на сервер:

&НаКлиенте
Процедура НоменклатураПриИзменении(Элемент)
    ЗаполнитьЦенуНаСервере();
КонецПроцедуры

&НаСервере
Процедура ЗаполнитьЦенуНаСервере()
    Объект.Цена = ЦенаНаДату(Объект.Номенклатура, Объект.Дата);
КонецПроцедуры

Быстро — по сети идут две ссылки и число:

&НаКлиенте
Процедура НоменклатураПриИзменении(Элемент)
    Объект.Цена = ЦенаНаДату(Объект.Номенклатура, Объект.Дата);
КонецПроцедуры

&НаСервереБезКонтекста
Функция ЦенаНаДату(Номенклатура, Дата)
    Запрос = Новый Запрос;
    Запрос.Текст =
    "ВЫБРАТЬ
    |    Цены.Цена КАК Цена
    |ИЗ
    |    РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Дата, Номенклатура = &Номенклатура) КАК Цены";
    Запрос.УстановитьПараметр("Дата", Дата);
    Запрос.УстановитьПараметр("Номенклатура", Номенклатура);
    Выборка = Запрос.Выполнить().Выбрать();
    Возврат ?(Выборка.Следующий(), Выборка.Цена, 0);
КонецФункции

Имя регистра и его измерения в примере условные — подставьте свои из конфигурации.

Переменные модуля формы на сервере не сохраняются

Клиентская переменная &НаКлиенте Перем живёт, пока открыта форма. Серверная переменная модуля формы инициализируется заново при каждом вызове сервера. Положили в неё значение в одном вызове — в следующем там снова Неопределено. Хранить данные между вызовами нужно в реквизитах формы или во временном хранилище (ПоместитьВоВременноеХранилище).

Ещё два приёма для экономии вызовов

  • 🔁 Общий модуль с повторным использованием возвращаемых значений («На время сеанса» или «На время вызова») кэширует результаты. Повторный вызов с теми же параметрами не идёт на сервер. Подходит для настроек и констант, которые редко меняются.
  • 🏷 ПредопределенноеЗначение("Перечисление.СтавкиНДС.НДС20") работает на клиенте. Ради сравнения с предопределённым значением ходить на сервер не нужно.

Где контекст встречается на практике

СитуацияКакой контекстНа что смотреть
Обработчик формы ПриСозданииНаСервереСервер с контекстом формыМожно читать Параметры и заполнять реквизиты
Модуль объекта ПередЗаписьюСервер, контекст объектаЭтотОбъект, реквизиты, ОбменДанными.Загрузка
Фоновое заданиеОтдельный серверный сеансНет формы и клиентских переменных; всё передаётся параметрами
Регламентное заданиеСерверный сеанс от имени указанного пользователяНет интерактивных методов, Сообщить пользователь не увидит
Внешнее соединение (COM)Контекст «Внешнее соединение»Доступны только модули с этим флажком
HTTP-сервис, веб-сервисСервер без формыДанные — из запроса, ответ — через объект ответа
Расширение конфигурацииКонтекст расширяемого модуля&Перед, &После, &Вместо видят переменные исходного модуля

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

В регламентных и фоновых заданиях также не работают диалоги вроде Вопрос() и ПоказатьПредупреждение(). Сообщения пишут в журнал регистрации через ЗаписьЖурналаРегистрации().

Ошибки, связанные с контекстом, и что с ними делать

Диагностика: выберите симптом

Отдельно про производительность. Формально ошибкой это не считается, но вызов &НаСервере в обработчике ПриИзменении поля табличной части замедляет ввод на каждой строке. Если форма «подвисает» при наборе, первым делом проверьте директивы обработчиков.

Отладка: как увидеть, в каком контексте выполняется код

Остановитесь в нужной точке

Поставьте точку останова (F9) и запустите отладку. Когда выполнение остановится, откройте «Вычислить выражение» (Shift+F9) и введите имя переменной. Если в ответ пришла ошибка, имени нет в текущем контексте — значит, вы на другой стороне или в другом модуле.

Посмотрите стек вызовов

Окно стека вызовов (Ctrl+Alt+C) показывает цепочку процедур, которая привела к текущей строке. По нему видно, где клиентский код передал управление серверу. Типичная находка — цепочка из трёх-четырёх лишних переходов на сервер, которые можно схлопнуть в один.

Если серверные точки останова не срабатывают

В файловом варианте серверный код отлаживается сразу. В клиент-серверном варианте сервер 1С нужно запустить с поддержкой отладки: агент сервера ragent стартует с ключом -debug. Обычно ключ дописывают в параметры запуска службы агента.

Перезапуск службы агента сервера обрывает все сеансы пользователей этого кластера. Делайте это в нерабочее время или на тестовом сервере. На рабочем сервере режим отладки без нужды не держите — он добавляет нагрузку.

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

Замер производительности

Режим замера производительности в отладчике показывает, сколько времени заняла каждая строка. Если на строке вызова серверной процедуры висит большая доля времени при простом коде внутри, причина обычно в объёме данных формы, которые уходят на сервер. Это сигнал перевести процедуру в &НаСервереБезКонтекста.

Частые вопросы о контексте в 1С

Чем &НаСервере отличается от &НаСервереБезКонтекста?
Первая директива передаёт на сервер данные формы и возвращает их обратно. Вторая передаёт только параметры, поэтому работает быстрее, но не видит реквизиты и элементы формы.
Можно ли из серверной процедуры вызвать клиентскую?
Нет. Сервер возвращает результат клиенту через возвращаемое значение или реквизиты формы, а клиент уже решает, что делать дальше.
Зачем нужна директива &НаКлиентеНаСервереБезКонтекста?
Для небольших функций, которые нужны и там, и там: форматирование строк, расчёты по переданным параметрам. Функция выполняется на той стороне, откуда её вызвали, без лишнего вызова сервера.
Что такое ЭтотОбъект в модуле формы?
Сама форма. В модуле объекта ЭтотОбъект — это объект справочника или документа. Данные документа в форме доступны через основной реквизит Объект.
Где выполняется код модуля менеджера?
На сервере. Экспортные процедуры модуля менеджера вызывают через менеджер, например Справочники.Номенклатура.Метод(), из серверного кода.