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