Работа с клиент-серверной архитектурой в 1С:Предприятие требует чёткого понимания, где и как выполняются те или иные процедуры. Ошибки в разделении логики между клиентом и сервером могут привести к критическим проблемам производительности, блокировкам данных или даже падению системы. Эта статья поможет разобраться, как правильно организовать выполнение процедур на клиенте, когда это действительно необходимо, и какие механизмы для этого предоставляет платформа.
В отличие от серверных процедур, которые обрабатываются на стороне сервера баз данных, клиентские процедуры выполняются непосредственно на рабочей станции пользователя. Это даёт ряд преимуществ — например, снижение нагрузки на сервер или возможность работы с локальными ресурсами (файлами, оборудованием). Однако непродуманное использование клиентского кода может стать источником ошибок, особенно в многопользовательских конфигурациях. Далее мы рассмотрим не только базовые методы запуска, но и нюансы, о которых часто умалчивают в стандартной документации.
Что такое "клиентская процедура" в 1С и когда её использовать
Клиентская процедура — это фрагмент кода, который исполняется на компьютере пользователя, а не на сервере 1С:Предприятия. Основное отличие от серверных процедур заключается в контексте выполнения: клиентский код имеет доступ к локальным ресурсам (например, файловой системе или подключённым устройствам), но не может напрямую взаимодействовать с базой данных без обращения к серверу.
Когда стоит выносить логику на клиент?
- 📁 Работа с файлами: чтение/запись документов на локальном диске пользователя (например, экспорт отчётов в Excel или загрузка изображений).
- 🖥️ Взаимодействие с оборудованием: печать на локальном принтере, сканирование штрихкодов через подключённое устройство.
- ⚡ Оптимизация производительности: если процедура требует интенсивных вычислений, но не затрагивает данные базы (например, сложные математические расчёты в отчётах).
- 🎨 Интерактивные элементы интерфейса: динамическое изменение формы без обращения к серверу (например, валидация введённых данных в реальном времени).
Также клиентские процедуры выполняются в контексте текущего сеанса пользователя, что накладывает ограничения на доступ к некоторым объектам конфигурации.
⚠️ Внимание: Если ваша процедура модифицирует данные в базе (например, изменяет записи в справочниках или документах), её обязательно нужно выполнять на сервере. Клиентский код может только инициировать серверные вызовы через механизмы платформы.
Способы объявления клиентских процедур в 1С
В 1С:Предприятие 8.3 есть несколько способов указать, что процедура должна выполняться на клиенте. Выбор метода зависит от контекста и задачи:
- Директива компиляции
&НаКлиенте— самый распространённый способ. Она размещается перед объявлением процедуры или функции:&НаКлиентеПроцедура МояПроцедура()
// Код выполняется на клиенте
КонецПроцедуры
- Контекстное меню в конфигураторе: при создании процедуры в модуле формы или объекта можно выбрать вариант выполнения ("На клиенте", "На сервере", "На клиенте и на сервере").
- Динамическое определение контекста с помощью функции
ТипЗначенияСтр(ЭтотОбъект)или проверкиКлиентНаСервере()(актуально для универсальных процедур).
Также стоит учитывать, что клиентские процедуры могут быть:
- 📌 Локальными — доступны только в рамках текущего модуля (например, в модуле формы).
- 🌐 Глобальными — объявлены в общем модуле с установленным флагом "Клиент (управляемое приложение)".
Пример объявления клиентской процедуры в общем модуле:
&НаКлиенте
Процедура ПоказатьСообщениеПользователю(Текст) Экспорт
Сообщить(Текст, СтатусСообщения.Важно);
КонецПроцедуры
⚠️ Внимание: Если вы используете клиентские процедуры в тонком клиенте или веб-клиенте, учитывайте ограничения на доступ к локальным ресурсам (например, работа с файлами может быть заблокирована по умолчанию в браузере).
Как вызвать клиентскую процедуру из серверного кода
Иногда требуется инициировать выполнение клиентского кода из серверной процедуры — например, после завершения длительной операции на сервере. Для этого в 1С:Предприятие предусмотрен механизм асинхронных вызовов с использованием метода ВыполнитьНаКлиенте().
Базовый синтаксис:
ВыполнитьНаКлиенте("ИмяПроцедуры", Параметр1, Параметр2);
Пример: после сохранения документа на сервере нужно показать пользователю уведомление на клиенте:
&НаСервере
Процедура СохранитьДокумент()
// Логика сохранения на сервере
Документ.Записать();
// Вызов клиентской процедуры после сохранения
ВыполнитьНаКлиенте("ПоказатьУспехСохранения");
КонецПроцедуры
&НаКлиенте
Процедура ПоказатьУспехСохранения()
Сообщить("Документ успешно сохранён!", СтатусСообщения.Информация);
КонецПроцедуры
Особенности использования ВыполнитьНаКлиенте():
- 🔄 Можно передавать параметры клиентской процедуре (примитивные типы, строки, числа).
- ⏳ Вызов выполняется асинхронно — серверный код не ждёт завершения клиентской процедуры.
- 🚫 Нельзя передавать сложные объекты (например, ссылки на документы) — только сериализуемые данные.
Если вам нужно дождаться завершения клиентской процедуры перед продолжением работы на сервере, используйте механизм Ожидание с флагами или организуйте обратный вызов через событие.
Ошибки при работе с клиентскими процедурами и как их избежать
Неправильное использование клиентского кода может привести к трудноуловимым ошибкам. Рассмотрим типичные проблемы и способы их решения:
| Ошибка | Причина | Решение |
|---|---|---|
Ошибка при вызове метода объекта (ВыполнитьНаКлиенте) |
Попытка вызвать несуществующую клиентскую процедуру или передать несериализуемый параметр. | Проверьте имя процедуры и типы передаваемых данных. Используйте примитивные типы или Структура. |
Доступ к файлу запрещён (в веб-клиенте) |
Попытка записи/чтения файла на клиенте в браузере без соответствующих разрешений. | Используйте ФайловыйДиалог для выбора файла пользователем или перенесите логику на сервер. |
| Зависание интерфейса при длительном выполнении | Клиентская процедура блокирует основной поток (например, при сложных расчётах). | Разбейте задачу на части или используйте BackgroundWorker (в толстом клиенте). |
Недостаточно прав для выполнения операции |
Клиентская процедура пытается выполнить действие, требующее серверных прав (например, изменение данных). | Вынесите модификацию данных в серверную процедуру и вызовите её из клиентского кода. |
Одна из самых распространённых ошибок — попытка обратиться к серверным данным напрямую из клиентской процедуры. Например, такой код вызовет ошибку:
&НаКлиенте
Процедура ОшибочныйКод()
// ❌ Ошибка: обращение к серверным данным без контекста сервера
Документ = Документы.ЗаказКлиента.СоздатьДокумент();
КонецПроцедуры
Правильный вариант:
&НаКлиенте
Процедура ПравильныйКод()
// ✅ Вызов серверной процедуры для работы с данными
СервернаяПроцедураСоздатьЗаказ();
КонецПроцедуры
&НаСервере
Процедура СервернаяПроцедураСоздатьЗаказ()
Документ = Документы.ЗаказКлиента.СоздатьДокумент();
//.. остальная логика
КонецПроцедуры
Почему нельзя создавать документы на клиенте?
На клиенте отсутствует прямой доступ к менеджерам объектов (например, Документы.ЗаказКлиента), так как они требуют серверного контекста. Платформа 1С:Предприятие разграничивает доступ к данным для обеспечения безопасности и целостности информации. Попытка создать или изменить объект на клиенте приведёт к исключению "Объект не найден" или "Нет прав на выполнение операции".
Оптимизация клиентских процедур: советы разработчикам
Клиентский код должен быть не только функциональным, но и оптимизированным — особенно если он выполняется в многопользовательском режиме. Вот несколько рекомендаций:
- Минимизируйте обращения к серверу:
- 📥 Запрашивайте данные пакетами (например, через
Выбрать()с ограничением по количеству строк). - 🔄 Используйте кэширование часто используемых данных на клиенте (например, справочники с небольшим количеством записей).
- 📥 Запрашивайте данные пакетами (например, через
- Избегайте тяжелых вычислений в основном потоке:
- ⏳ Для длительных операций (например, генерация отчётов) используйте
BackgroundWorker(в толстом клиенте) или разбивайте задачу на части. - 📊 Для сложных расчётов рассмотрите возможность переноса логики на сервер (если данные всё равно нужны с сервера).
- ⏳ Для длительных операций (например, генерация отчётов) используйте
- 🎨 Отключайте автоматическое обновление формы (
АвтоОбновление = Ложь) при массовых изменениях. - 🔍 Используйте
НайтиЭлемент()вместо перебора всех элементов формы в цикле.
Пример оптимизированного кода для загрузки данных на клиент:
&НаКлиенте
Процедура ЗагрузитьДанные()
// ✅ Оптимизированный запрос: загружаем только нужные поля
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 100
| Номенклатура.Ссылка КАК Ссылка,
| Номенклатура.Наименование КАК Наименование
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| Номенклатура.ПометкаУдаления = ЛОЖЬ";
Результат = Запрос.Выполнить().Выбрать();
Пока Результат.Следующий() Цикл
// Обработка данных на клиенте
КонецЦикла;
КонецПроцедуры
Используются ли пакетные запросы к серверу?|Отключено ли автоматическое обновление формы при массовых операциях?|Тяжёлые вычисления вынесены в фоновый поток или на сервер?|Минимизировано ли количество обращений к файловой системе?|Используется ли кэширование для часто запрашиваемых данных?
-->
Практические примеры: от простого к сложному
Рассмотрим несколько реальных сценариев, где клиентские процедуры незаменимы.
Пример 1: Экспорт данных в Excel
Задача: предоставить пользователю возможность сохранить таблицу документов в файл Excel на локальном диске.
&НаКлиенте
Процедура ЭкспортироватьВExcel(ТаблицаДанных)
// Создаём объект Excel
Excel = Новый COMОбъект("Excel.Application");
Книга = Excel.Workbooks.Add();
Лист = Книга.Worksheets(1);
// Заполняем данные
Для Каждого Строка Из ТаблицаДанных Цикл
НомерСтроки = Строка.Индекс + 1;
Для Каждого Колонка Из Строка.Колонки Цикл
Лист.Cells(НомерСтроки, Колонка.Индекс + 1).Value = Колонка.Значение;
КонецЦикла;
КонецЦикла;
// Сохраняем файл
Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Сохранение);
Если Диалог.Выбрать() Тогда
ПутьКФайлу = Диалог.ПолноеИмяФайла;
Книга.SaveAs(ПутьКФайлу);
Сообщить("Файл сохранён: " + ПутьКФайлу);
КонецЕсли;
// Закрываем Excel
Книга.Close();
Excel.Quit();
КонецПроцедуры
⚠️ Внимание: В веб-клиенте и тонком клиенте работа сCOMОбъект("Excel.Application")может быть заблокирована по соображениям безопасности. В этом случае используйте альтернативные методы экспорта, например, черезЗаписьJSONили специализированные библиотеки.
Пример 2: Динамическая валидация данных в форме
Задача: проверять корректность введённого пользователем email-адреса в реальном времени (без обращения к серверу).
&НаКлиенте
Процедура EmailПриИзменении(Элемент)
Email = Элемент.Значение;
Если НЕ РегулярноеВыражение("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$").Совпадение(Email) Тогда
Элемент.УстановитьОшибку("Некорректный email-адрес");
Иначе
Элемент.СброситьОшибку();
КонецЕсли;
КонецПроцедуры
Пример 3: Работа с локальным принтером
Задача: распечатать документ на принтере, подключённом к рабочей станции пользователя.
&НаКлиенте
Процедура ПечатьДокумента(Документ)
// Формируем печатную форму на клиенте
ПечатнаяФорма = ПолучитьПечатнуюФорму(Документ);
// Настройка печати
ПараметрыПечати = Новый Структура;
ПараметрыПечати.Вставить("ИмяПринтера", "HP LaserJet P1102");
ПараметрыПечати.Вставить("Копий", 1);
// Печать
ПечатнаяФорма.Печать(ПараметрыПечати);
КонецПроцедуры
Во всех примерах клиентский код решает задачи, которые нельзя или нецелесообразно выполнять на сервере: взаимодействие с локальным ПО, валидация в реальном времени, работа с оборудованием.
Отладка клиентских процедур: инструменты и техника
Отладка клиентского кода в 1С:Предприятие имеет свои особенности. Вот ключевые инструменты и приёмы:
- 🐞 Отладчик в конфигураторе:
- Установите точку останова (
F9) в клиентской процедуре. - Запустите отладку в режиме "1С:Предприятие" (
F5). - Используйте
F10(шаг с заходом) иF11(шаг с обходом) для пошагового выполнения.
- Установите точку останова (
- 📝 Журнал сообщений:
- Используйте
Сообщить()для вывода отладочной информации. - Включите запись журнала сообщений в настройках запуска (
Отладка → Настройки → Записывать сообщения в журнал).
- Используйте
- 🔍 Анализ производительности:
- Включите
Тестирование и исправление → Измерить производительность. - Обратите внимание на время выполнения клиентских процедур — если оно превышает 1-2 секунды, рассмотрите оптимизацию.
- Включите
Пример отладочного кода для клиентской процедуры:
&НаКлиенте
Процедура ТестоваяПроцедура()
Сообщить("Начало выполнения клиентской процедуры", СтатусСообщения.Информация);
Начало = ТекущаяДата();
//.. основной код процедуры
Конец = ТекущаяДата();
Сообщить("Время выполнения: " + (Конец - Начало) + " мс", СтатусСообщения.Обычное);
КонецПроцедуры
Для отладки асинхронных вызовов (например, после ВыполнитьНаКлиенте()) используйте условные точки останова или вывод в журнал, так как стандартный отладчик может не захватывать такие вызовы.
Если клиентская процедура работает нестабильно в веб-клиенте, проверьте:
- 🔒 Настройки безопасности браузера (разрешения на выполнение скриптов).
- 📡 Стабильность интернет-соединения (потери пакетов могут прерывать выполнение).
- 🛠️ Версию браузера и его совместимость с текущей версией платформы 1С.
FAQ: Частые вопросы по клиентским процедурам в 1С
Можно ли из клиентской процедуры обратиться к базе данных напрямую?
Нет, клиентский код не имеет прямого доступа к базе данных. Для работы с данными необходимо вызывать серверные процедуры через механизмы платформы (например, ВыполнитьНаСервере()). Это правило действует даже если вы работаете в толстом клиенте — платформа жёстко разграничивает контексты выполнения.
Как передать сложный объект (например, документ) из серверной процедуры в клиентскую?
Прямая передача ссылок на объекты базы (документов, справочников) в клиентскую процедуру невозможна. Вместо этого передавайте:
- Идентификаторы объектов (например,
Документ.Ссылка.УникальныйИдентификатор()). - Сериализуемые данные (строки, числа, структуры, массивы).
На клиенте можно получить полный объект по идентификатору через вызов серверной процедуры:
&НаКлиенте
Процедура ПолучитьДокументПоИдентификатору(Ид)
Документ = ВыполнитьНаСервере("НаСервереПолучитьДокумент", Ид);
КонецПроцедуры
&НаСервере
Функция НаСервереПолучитьДокумент(Ид)
Возврат Документы.ЗаказКлиента.НайтиПоИдентификатору(Ид);
КонецФункции
Почему клиентская процедура работает в толстом клиенте, но не работает в веб-клиенте?
Это связано с ограничениями веб-клиента:
- 🚫 Запрещена работа с
COMОбъект(например, Excel, Word). - 📁 Ограничен доступ к локальной файловой системе (требуется использование диалогов выбора файлов).
- 🔌 Некоторые API платформы могут быть недоступны или работать иначе.
Решение: используйте кросс-платформенные методы (например, ЗаписьJSON вместо Excel) или реализуйте альтернативную логику для веб-клиента.
Как сделать так, чтобы клиентская процедура выполнялась в фоновом режиме?
В толстом клиенте можно использовать объект BackgroundWorker для выполнения кода в отдельном потоке:
&НаКлиенте
Процедура ЗапуститьФоновуюЗадачу()
Работник = Новый BackgroundWorker;
Работник.ВыполнитьАсинхронно("ФоноваяПроцедура", 10); // Передаём параметр
КонецПроцедуры
&НаКлиенте
Процедура ФоноваяПроцедура(Параметр) Экспорт
// Код выполняется в фоновом потоке
Сообщить("Фоновая задача завершена с параметром: " + Параметр);
КонецПроцедуры
В тонком и веб-клиенте фоновые задачи не поддерживаются — используйте разбиение длительных операций на части с паузами (Подождать()).
Можно ли из клиентской процедуры вызвать другую клиентскую процедуру асинхронно?
Платформа 1С:Предприятие не поддерживает прямые асинхронные вызовы между клиентскими процедурами. Однако можно эмулировать асинхронность:
- С помощью
Подождать()для коротких задержек. - Через механизм событий (например, установить флаг и обработать его в основном цикле).
- В толстом клиенте — с использованием
BackgroundWorker.
Пример с Подождать():
&НаКлиенте
Процедура АсинхронныйВызов()
// Запускаем "асинхронно" через небольшую задержку
Подождать(1); // 1 мс
ДругаяКлиентскаяПроцедура();
КонецПроцедуры