Разработка и Конфигурация · 12 мин
Как выполнить процедуру на клиенте в 1С
Как выполнить процедуру на клиенте в 1С: директивы &НаКлиенте и &НаСервере, вызов серверных процедур из клиента, контекст формы, типичные ошибки и примеры кода.
В управляемых формах 1С код делится на клиентский и серверный, и платформа строго контролирует, где может выполняться каждая процедура. Чтобы процедура выполнилась на клиенте — то есть на компьютере пользователя, в контексте тонкого, толстого или веб-клиента — её нужно объявить с директивой компиляции &НаКлиенте и учитывать ограничения клиентского контекста.
Клиентский код нужен там, где требуется интерактивность: показать вопрос пользователю, открыть диалог выбора файла, запустить внешнее приложение, обработать событие элемента формы без обращения к серверу. Серверный код нужен для работы с базой данных, запросами и объектами, недоступными на клиенте. Правильное разделение — основа производительности управляемого приложения.
Ниже разобраны директивы компиляции, способы вызова клиентских и серверных процедур, работа с общими модулями, типичные ошибки вида «Процедура или функция с указанным именем не определена» и ограничения, о которых нужно помнить при переносе логики между клиентом и сервером.
Директивы компиляции: как платформа решает, где выполняется код
В модуле управляемой формы каждая процедура и функция помечается директивой компиляции. Директива указывает платформе, на какой стороне — клиенте или сервере — будет скомпилирован и выполнен код. Если директиву не указать, компилятор выдаст ошибку, потому что в управляемых формах «нейтрального» контекста не существует.
Основные директивы:
&НаКлиенте— процедура выполняется на клиенте, имеет доступ к элементам формы, может показывать диалоги и работать с файловой системой пользователя;&НаСервере— выполняется на сервере, имеет доступ к запросам, объектам базы данных, но не видит элементы формы напрямую;&НаСервереБезКонтекста— серверная процедура без доступа к данным формы; передача параметров только через аргументы;&НаКлиентеНаСервереБезКонтекста— код компилируется и там, и там; используется для простых вспомогательных функций без обращения к базе и к элементам формы.
Пример объявления клиентской процедуры:
&НаКлиенте
Процедура ПоказатьПредупреждениеПользователю()
ПоказатьПредупреждение(, "Операция выполнена на клиенте");
КонецПроцедуры
Как создать клиентскую процедуру в модуле формы
Откройте управляемую форму в конфигураторе, перейдите на вкладку «Модуль» и напишите процедуру с директивой &НаКлиенте. Самый частый сценарий — обработчик команды формы или события элемента. При создании обработчика через палитру свойств платформа сама предложит директиву, и для интерактивных действий правильный выбор — клиент.
Пример: кнопка «ОчиститьКаталог» должна очищать поле ввода без обращения к серверу. Обработчик выглядит так:
&НаКлиенте
Процедура ОчиститьКаталог(Команда)
Объект.КаталогОбмена = "";
КонецПроцедуры
Обратите внимание: данные реквизитов формы (например, Объект для формы документа) доступны и на клиенте, и на сервере — платформа синхронизирует их между сторонами. Но попытка выполнить запрос к базе или обратиться к менеджеру объекта (Документы.РеализацияТоваров) из клиентской процедуры приведёт к ошибке компиляции или выполнения.
- 1Откройте форму в конфигураторе и перейдите в модуль формы
- 2Напишите процедуру с директивой &НаКлиенте
- 3Привяжите её к команде или событию элемента через палитру свойств
- 4Проверьте, что внутри нет обращений к базе данных, запросов и менеджеров объектов
- 5Запустите режим предприятия и проверьте работу в том клиенте, который используется в продуктиве
Вызов серверной процедуры из клиентской
Поскольку клиент не имеет доступа к базе данных, любая операция чтения или записи требует вызова серверной процедуры из клиентской. В модуле формы это делается простым обращением по имени — платформа сама организует серверный вызов:
&НаКлиенте
Процедура ЗаполнитьОстатки(Команда)
КоличествоСтрок = ЗаполнитьОстаткиНаСервере();
ПоказатьОповещениеПользователя("Заполнено строк: " + КоличествоСтрок);
КонецПроцедуры
&НаСервере
Функция ЗаполнитьОстаткиНаСервере()
// запрос к базе, заполнение табличной части
Возврат Объект.Товары.Количество();
КонецФункции
Каждый такой вызов — это обращение к серверу по сети с сериализацией данных формы. Если вызывать сервер в цикле (например, для каждой строки таблицы), форма начнёт заметно тормозить. Правильный подход — собрать данные на клиенте в массив или структуру и передать их на сервер одним вызовом.
Директива &НаСервереБезКонтекста делает вызов дешевле: данные формы не передаются на сервер, но и обратиться к реквизитам формы внутри такой процедуры нельзя — всё нужное передаётся параметрами, а результат возвращается через Возврат.
Сравнение серверных вызовов
Видит реквизиты и данные формы, но передаёт весь контекст на сервер — вызов дороже. Подходит для операций над данными текущей формы.
Не видит данные формы, параметры передаются явно. Быстрее и предпочтительнее для вычислений, не привязанных к форме.
Вызывается с клиента, если у модуля включён флаг «Вызов сервера». Подходит для переиспользуемой логики вне конкретной формы.
Клиентские процедуры в общих модулях
Если клиентская логика нужна в нескольких формах, её выносят в общий модуль. Поведение модуля определяется его свойствами в конфигураторе:
- Клиент (управляемое приложение) — модуль компилируется на клиенте, процедуры доступны из клиентского кода;
- Сервер — модуль выполняется на сервере;
- Вызов сервера — разрешает обращение к серверному модулю с клиента;
- Клиент (обычное приложение) — для обычных форм, в современных конфигурациях обычно не используется.
Общий модуль с одновременно включёнными флагами «Клиент» и «Сервер» компилируется в обоих контекстах — внутри него можно использовать инструкции препроцессора #Если Клиент Тогда ... #КонецЕсли, но злоупотреблять этим не стоит: код становится труднее сопровождать.
Вызов клиентской процедуры из общего модуля выглядит так: ОбщегоНазначенияКлиент.СообщитьПользователю(...). Если модуль серверный с вызовом сервера — имя модуля доступно и в клиентской процедуре, но каждый вызов снова идёт по сети.
Асинхронные вызовы и описания оповещений
Клиентские процедуры часто работают в паре через механизм оповещений: одна процедура запускает асинхронную операцию (вопрос, выбор файла, помещение файла во временное хранилище), а вторая — обрабатывает результат. Обе должны быть клиентскими.
&НаКлиенте
Процедура ПередЗакрытиемПодтвердить(Команда)
Оповещение = Новый ОписаниеОповещения("ПослеОтветаНаВопрос", ЭтотОбъект);
ПоказатьВопрос(Оповещение, "Закрыть без сохранения?", РежимДиалогаВопрос.ДаНет);
КонецПроцедуры
&НаКлиенте
Процедура ПослеОтветаНаВопрос(Результат, ДополнительныеПараметры) Экспорт
Если Результат = КодВозвратаДиалога.Да Тогда
Закрыть();
КонецЕсли;
КонецПроцедуры
Типичная ошибка здесь — забыть слово Экспорт у процедуры-обработчика. Платформа вызывает её извне модуля по имени, поэтому без экспорта получите ошибку «Процедура или функция с указанным именем не определена» в момент срабатывания оповещения.
Ограничения клиентского контекста
На клиенте недоступны: запросы и построитель отчёта, менеджеры объектов и справочников, проведение документов, привилегированный режим, большинство прикладных серверных механизмов. Клиент работает только с данными, которые уже переданы в форму, и с ресурсами компьютера пользователя — файловой системой, внешними компонентами, COM-объектами (в толстом и тонком клиенте под Windows).
Есть и различия между клиентами. Веб-клиент не поддерживает COM и запуск внешних приложений без расширения работы с файлами; тонкий клиент требует установки расширения для работы с файлами. Поэтому код, работающий с файлами, должен проверять подключение расширения через ПодключитьРасширениеРаботыСФайлами — тоже асинхронно.
Ещё одно ограничение — безопасность: вся логика на клиенте потенциально доступна пользователю. Проверки прав, критичные расчёты цен и скидок, контроль остатков обязаны дублироваться или выполняться на сервере, иначе их можно обойти.
Как проверить, что процедура выполняется на клиенте
Самый простой способ — отладка. Поставьте точку останова в клиентской процедуре и запустите отладку: в конфигураторе в списке подключённых предметов отладки будет виден клиентский сеанс. Также можно временно добавить вывод ТипКлиентскогоПриложения через ТекущийРежимЗапуска() и информацию из ПолучитьИнформациюЭкрановКлиента() — эти функции доступны только на клиенте.
Косвенный признак правильного разделения — поведение формы: клиентские операции выполняются мгновенно без «подвисания» формы, а серверные вызовы в журнале технологического события фиксируются как обращения к серверу. Если простое действие в форме вызывает паузу — вероятно, внутри клиентского обработчика спрятался лишний серверный вызов.
Как проверить результат
Нет ошибок о недоступности методов в клиентском контексте
Ошибки вида «Процедура или функция не определена» или «Метод не обнаружен»
Интерактивные действия выполняются мгновенно, без пауз
Каждый клик вызывает задержку — лишние серверные вызовы
Все диалоги и файловые операции работают через расширение
Ошибки модальности или недоступности COM-объектов
Частые вопросы
Можно ли вызвать клиентскую процедуру с сервера?
Нет, прямой вызов с сервера на клиент невозможен — сервер не знает о состоянии клиента. Обратная связь организуется через возврат значения из серверной процедуры в клиентскую, через оповещения (Оповестить уже на клиенте после получения результата) или через систему взаимодействия в специальных сценариях.
Чем &НаСервереБезКонтекста лучше &НаСервере?
Процедура без контекста не передаёт данные формы на сервер, поэтому вызов быстрее и дешевле по сети. Но обратиться к реквизитам формы внутри неё нельзя — всё передаётся параметрами. Используйте её для функций, которым нужны только входные аргументы: расчёты, обращения к справочникам, проверки.
Почему клиентская процедура не видна из другого модуля?
Процедуры модуля формы недоступны извне — форма не является глобальным контекстом. Выносите переиспользуемый код в общий модуль с флагом «Клиент (управляемое приложение)» и добавляйте Экспорт к процедурам, которые должны вызываться снаружи.
Как выполнить процедуру на клиенте по расписанию?
Через обработчик ожидания: ПодключитьОбработчикОжидания("ИмяПроцедуры", 60) в клиентском контексте. Процедура-обработчик должна быть клиентской и экспортной. Для отключения используйте ОтключитьОбработчикОжидания. Учтите, что обработчик работает только пока открыт клиентский сеанс.
Работает ли клиентский код одинаково в тонком и веб-клиенте?
Базовая логика — да, но есть отличия: веб-клиент не поддерживает COM-объекты и запуск приложений, требует расширения для файловых операций и не допускает модальных окон. Проверяйте функциональность в том типе клиента, который реально используют пользователи.
Что важно запомнить
Клиентская процедура объявляется с директивой &НаКлиенте в модуле формы или размещается в общем модуле с флагом «Клиент». Работа с базой данных возможна только через вызов серверных процедур, причём вызовы следует минимизировать и не выполнять в циклах. Асинхронные операции оформляются через описания оповещений с экспортными обработчиками, а критичные проверки всегда дублируются на сервере.