К статье
Практический материал

Разработка и Конфигурация · 12 мин

Какие бывают директивы в 1С и как их применять

Разбираем директивы компиляции &НаКлиенте, &НаСервере, инструкции препроцессора #Если и аннотации методов в 1С: назначение, синтаксис, примеры и типичные ошибки.

Директивы в 1С — это специальные инструкции, которые управляют тем, где и как будет исполняться код. Они не выполняют прикладную логику сами по себе, но определяют контекст компиляции и выполнения процедур и функций. Ошибка в выборе директивы — одна из самых частых причин сообщений вида «Процедура или функция с указанным именем не определена» и лишних серверных вызовов, замедляющих работу формы.

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

Понимание директив критично при работе с управляемыми формами, потому что именно там код распределяется между клиентом и сервером. В обычных формах и толстом клиенте большинство директив компиляции просто не имеет смысла — весь код выполняется на клиенте.

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

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

Всего существует четыре директивы компиляции:

  • &НаКлиенте — метод компилируется и выполняется на клиенте. Доступны интерактивные действия: вопросы пользователю, открытие форм, работа с файловой системой клиента. Недоступны прямые запросы к базе данных и серверный контекст.
  • &НаСервере — метод выполняется на сервере с доступом к данным формы. Можно работать с запросами, объектами базы данных, при этом реквизиты формы доступны через контекст.
  • &НаСервереБезКонтекста — метод выполняется на сервере, но данные формы в него не передаются. Такой вызов дешевле по ресурсам, потому что не требует сериализации всей формы.
  • &НаКлиентеНаСервереБезКонтекста — метод компилируется и на клиенте, и на сервере, без контекста формы. Используется для общих вспомогательных алгоритмов, например расчётов или форматирования, которые одинаково нужны с обеих сторон.
bsl
&НаКлиенте
Процедура РассчитатьИтог(Команда)
	РассчитатьИтогНаСервере();
КонецПроцедуры

&НаСервереБезКонтекста
Процедура РассчитатьИтогНаСервере()
	// работа с данными без контекста формы
КонецПроцедуры

Важно помнить: директива &НаКлиентеНаСервереБезКонтекста в модуле формы по факту работает только на сервере при вызове из серверного кода и только на клиенте при вызове из клиентского — переключения контекста она не выполняет. Для вызова сервера из клиента нужен именно серверный метод.

Как выбрать правильную директиву компиляции

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

Маршрут решения

Как выбрать действие

Нужен запрос к базе или изменение объектов данныхИспользуйте &НаСервере или &НаСервереБезКонтекста
Нужен доступ к реквизитам и элементам текущей формы на сервереИспользуйте &НаСервере — контекст формы будет передан
Достаточно передать параметры, данные формы не нужныИспользуйте &НаСервереБезКонтекста — вызов будет быстрее
Нужны диалоги, предупреждения, работа с файлами пользователяИспользуйте &НаКлиенте
Одинаковый расчёт нужен и на клиенте, и на сервереИспользуйте &НаКлиентеНаСервереБезКонтекста или общий модуль с флагами Клиент и Сервер

Частая ошибка — помечать &НаСервере методы, которым достаточно передать два-три параметра. Каждый такой вызов сериализует всю форму, пересылает её на сервер и обратно, что при большом числе реквизитов и табличных частей заметно тормозит интерфейс. Перепишите метод на &НаСервереБезКонтекста и передавайте только нужные данные параметрами.

Инструкции препроцессора: условная компиляция

Вторая группа директив — инструкции препроцессора. Они работают на этапе компиляции модуля и позволяют включать или исключать фрагменты кода в зависимости от среды исполнения. Синтаксис строится на конструкциях #Если ... #ИначеЕсли ... #Иначе ... #КонецЕсли.

Доступные символы препроцессора:

  • Клиент — код компилируется для любого клиентского приложения;
  • ТонкийКлиент, ВебКлиент, ТолстыйКлиентУправляемоеПриложение, ТолстыйКлиентОбычноеПриложение — конкретные виды клиентов;
  • Сервер — код компилируется на сервере;
  • ВнешнееСоединение — код выполняется в режиме внешнего соединения (COM);
  • МобильныйКлиент, МобильноеПриложениеКлиент, МобильноеПриложениеСервер — для мобильной платформы.
bsl
#Если Сервер Тогда
	Сообщить("Выполняется на сервере");
#ИначеЕсли ВебКлиент Тогда
	// ограниченная функциональность веб-клиента
#Иначе
	// тонкий или толстый клиент
#КонецЕсли

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

Аннотации методов в расширениях конфигурации

Третья группа директив появилась вместе с механизмом расширений. Аннотации указывают, как заимствованный метод соотносится с методом основной конфигурации. Они ставятся перед процедурой или функцией в модуле расширения.

  • &Перед("ИмяМетода") — метод расширения выполняется до метода конфигурации;
  • &После("ИмяМетода") — выполняется после метода конфигурации;
  • &Вместо("ИмяМетода") — полностью замещает метод конфигурации; вызвать исходный можно через ПродолжитьВызов();
  • &ИзменениеИКонтроль("ИмяМетода") — метод копируется в расширение целиком с вставками-изменениями; при обновлении конфигурации платформа помогает отследить расхождения с новой версией исходного метода.

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

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

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

Также существуют ограничения на передаваемые типы. В &НаСервереБезКонтекста нельзя передать данные формы напрямую — только сериализуемые значения: примитивы, структуры, массивы, ссылки. Попытка передать, например, ДанныеФормы приведёт к ошибке исполнения.

Типичные ошибки
01
Объявление метода &НаСервере там, где контекст не нужен — лишняя сериализация формы и медленная работа
02
Вызов клиентского метода из серверного кода — ошибка компиляции или выполнения, так как на сервере клиентский метод отсутствует
03
Передача несериализуемых типов (например, элементов формы) в серверный метод — ошибка при вызове
04
Использование #Если Сервер внутри метода &НаКлиенте — серверная ветка просто не будет скомпилирована
05
Забытая директива перед обработчиком команды в модуле команды — метод не находится при выполнении

Где какие директивы применяются

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

Тип модуляДирективы компиляцииПрепроцессор
Модуль управляемой формыВсе четыреДа
Модуль команды&НаКлиенте, &НаСервереДа
Общий модульНет (контекст задаётся флагами)Да
Модуль объекта / менеджераНетДа
Модуль расширенияАннотации &Перед, &После, &Вместо, &ИзменениеИКонтрольДа

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

Контрольные точки

Как проверить результат

Доступность метода
Норма

Метод вызывается из нужного контекста без ошибок компиляции

Тревожный признак

Сообщение «Процедура или функция с указанным именем не определена»

Производительность формы
Норма

Серверные вызовы без контекста, форма откликается быстро

Тревожный признак

Каждое действие пересылает всю форму на сервер, заметны задержки

Работа расширения после обновления
Норма

Методы &ИзменениеИКонтроль показывают расхождения, логика актуализирована

Тревожный признак

Методы &Вместо молча замещают обновлённую типовую логику

Практические рекомендации по оформлению кода

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

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

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

Что важно запомнить

Директивы компиляции (&НаКлиенте, &НаСервере и варианты без контекста) определяют место выполнения методов формы. Препроцессор (#Если) включает код по среде исполнения. Аннотации расширений (&Перед, &После, &Вместо, &ИзменениеИКонтроль) управляют заимствованием методов. Правильный выбор директивы влияет на скорость работы и сопровождаемость конфигурации.

Частые вопросы о директивах 1С

Чем &НаСервере отличается от &НаСервереБезКонтекста?

Метод &НаСервере получает весь контекст формы — реквизиты, табличные части, элементы. Метод &НаСервереБезКонтекста работает изолированно и принимает только переданные параметры. Второй вариант быстрее, потому что не требует сериализации формы, поэтому его предпочитают, когда данные формы не нужны.

Можно ли вызвать клиентскую процедуру из серверной?

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

Зачем нужна директива &НаКлиентеНаСервереБезКонтекста, если есть общие модули?

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

Работают ли директивы компиляции в обычных формах?

В обычных формах (толстый клиент) весь код выполняется на клиенте, и директивы компиляции фактически не требуются. Их использование имеет смысл только в управляемых формах и модулях команд.

Что произойдёт, если в расширении два метода с &Перед на один исходный?

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

Как проверить, в каком контексте выполняется общий модуль?

Откройте свойства общего модуля в конфигураторе и посмотрите флаги «Клиент», «Сервер», «Внешнее соединение». Внутри кода можно использовать инструкции препроцессора #Если Сервер Тогда, чтобы убедиться, что нужная ветка компилируется в ожидаемой среде.