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