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