Работа с клиент-серверной архитектурой в 1С:Предприятие требует чёткого понимания, где и как выполняются те или иные процедуры. Ошибки в разделении логики между клиентом и сервером могут привести к критическим проблемам производительности, блокировкам данных или даже падению системы. Эта статья поможет разобраться, как правильно организовать выполнение процедур на клиенте, когда это действительно необходимо, и какие механизмы для этого предоставляет платформа.

В отличие от серверных процедур, которые обрабатываются на стороне сервера баз данных, клиентские процедуры выполняются непосредственно на рабочей станции пользователя. Это даёт ряд преимуществ — например, снижение нагрузки на сервер или возможность работы с локальными ресурсами (файлами, оборудованием). Однако непродуманное использование клиентского кода может стать источником ошибок, особенно в многопользовательских конфигурациях. Далее мы рассмотрим не только базовые методы запуска, но и нюансы, о которых часто умалчивают в стандартной документации.

Что такое "клиентская процедура" в 1С и когда её использовать

Клиентская процедура — это фрагмент кода, который исполняется на компьютере пользователя, а не на сервере 1С:Предприятия. Основное отличие от серверных процедур заключается в контексте выполнения: клиентский код имеет доступ к локальным ресурсам (например, файловой системе или подключённым устройствам), но не может напрямую взаимодействовать с базой данных без обращения к серверу.

Когда стоит выносить логику на клиент?

  • 📁 Работа с файлами: чтение/запись документов на локальном диске пользователя (например, экспорт отчётов в Excel или загрузка изображений).
  • 🖥️ Взаимодействие с оборудованием: печать на локальном принтере, сканирование штрихкодов через подключённое устройство.
  • Оптимизация производительности: если процедура требует интенсивных вычислений, но не затрагивает данные базы (например, сложные математические расчёты в отчётах).
  • 🎨 Интерактивные элементы интерфейса: динамическое изменение формы без обращения к серверу (например, валидация введённых данных в реальном времени).

Также клиентские процедуры выполняются в контексте текущего сеанса пользователя, что накладывает ограничения на доступ к некоторым объектам конфигурации.

⚠️ Внимание: Если ваша процедура модифицирует данные в базе (например, изменяет записи в справочниках или документах), её обязательно нужно выполнять на сервере. Клиентский код может только инициировать серверные вызовы через механизмы платформы.

Способы объявления клиентских процедур в 1С

В 1С:Предприятие 8.3 есть несколько способов указать, что процедура должна выполняться на клиенте. Выбор метода зависит от контекста и задачи:

  1. Директива компиляции &НаКлиенте — самый распространённый способ. Она размещается перед объявлением процедуры или функции:
    &НаКлиенте
    

    Процедура МояПроцедура()

    // Код выполняется на клиенте

    КонецПроцедуры

  2. Контекстное меню в конфигураторе: при создании процедуры в модуле формы или объекта можно выбрать вариант выполнения ("На клиенте", "На сервере", "На клиенте и на сервере").
  3. Динамическое определение контекста с помощью функции ТипЗначенияСтр(ЭтотОбъект) или проверки КлиентНаСервере() (актуально для универсальных процедур).

Также стоит учитывать, что клиентские процедуры могут быть:

  • 📌 Локальными — доступны только в рамках текущего модуля (например, в модуле формы).
  • 🌐 Глобальными — объявлены в общем модуле с установленным флагом "Клиент (управляемое приложение)".

Пример объявления клиентской процедуры в общем модуле:

&НаКлиенте

Процедура ПоказатьСообщениеПользователю(Текст) Экспорт

Сообщить(Текст, СтатусСообщения.Важно);

КонецПроцедуры

⚠️ Внимание: Если вы используете клиентские процедуры в тонком клиенте или веб-клиенте, учитывайте ограничения на доступ к локальным ресурсам (например, работа с файлами может быть заблокирована по умолчанию в браузере).
📊 Какой клиент 1С вы используете чаще всего?
Толстый клиент
Тонкий клиент
Веб-клиент
Мобильное приложение

Как вызвать клиентскую процедуру из серверного кода

Иногда требуется инициировать выполнение клиентского кода из серверной процедуры — например, после завершения длительной операции на сервере. Для этого в 1С:Предприятие предусмотрен механизм асинхронных вызовов с использованием метода ВыполнитьНаКлиенте().

Базовый синтаксис:

ВыполнитьНаКлиенте("ИмяПроцедуры", Параметр1, Параметр2);

Пример: после сохранения документа на сервере нужно показать пользователю уведомление на клиенте:

&НаСервере

Процедура СохранитьДокумент()

// Логика сохранения на сервере

Документ.Записать();

// Вызов клиентской процедуры после сохранения

ВыполнитьНаКлиенте("ПоказатьУспехСохранения");

КонецПроцедуры

&НаКлиенте

Процедура ПоказатьУспехСохранения()

Сообщить("Документ успешно сохранён!", СтатусСообщения.Информация);

КонецПроцедуры

Особенности использования ВыполнитьНаКлиенте():

  • 🔄 Можно передавать параметры клиентской процедуре (примитивные типы, строки, числа).
  • ⏳ Вызов выполняется асинхронно — серверный код не ждёт завершения клиентской процедуры.
  • 🚫 Нельзя передавать сложные объекты (например, ссылки на документы) — только сериализуемые данные.
💡

Если вам нужно дождаться завершения клиентской процедуры перед продолжением работы на сервере, используйте механизм Ожидание с флагами или организуйте обратный вызов через событие.

Ошибки при работе с клиентскими процедурами и как их избежать

Неправильное использование клиентского кода может привести к трудноуловимым ошибкам. Рассмотрим типичные проблемы и способы их решения:

Ошибка Причина Решение
Ошибка при вызове метода объекта (ВыполнитьНаКлиенте) Попытка вызвать несуществующую клиентскую процедуру или передать несериализуемый параметр. Проверьте имя процедуры и типы передаваемых данных. Используйте примитивные типы или Структура.
Доступ к файлу запрещён (в веб-клиенте) Попытка записи/чтения файла на клиенте в браузере без соответствующих разрешений. Используйте ФайловыйДиалог для выбора файла пользователем или перенесите логику на сервер.
Зависание интерфейса при длительном выполнении Клиентская процедура блокирует основной поток (например, при сложных расчётах). Разбейте задачу на части или используйте BackgroundWorker (в толстом клиенте).
Недостаточно прав для выполнения операции Клиентская процедура пытается выполнить действие, требующее серверных прав (например, изменение данных). Вынесите модификацию данных в серверную процедуру и вызовите её из клиентского кода.

Одна из самых распространённых ошибок — попытка обратиться к серверным данным напрямую из клиентской процедуры. Например, такой код вызовет ошибку:

&НаКлиенте

Процедура ОшибочныйКод()

// ❌ Ошибка: обращение к серверным данным без контекста сервера

Документ = Документы.ЗаказКлиента.СоздатьДокумент();

КонецПроцедуры

Правильный вариант:

&НаКлиенте

Процедура ПравильныйКод()

// ✅ Вызов серверной процедуры для работы с данными

СервернаяПроцедураСоздатьЗаказ();

КонецПроцедуры

&НаСервере

Процедура СервернаяПроцедураСоздатьЗаказ()

Документ = Документы.ЗаказКлиента.СоздатьДокумент();

//.. остальная логика

КонецПроцедуры

Почему нельзя создавать документы на клиенте?

На клиенте отсутствует прямой доступ к менеджерам объектов (например, Документы.ЗаказКлиента), так как они требуют серверного контекста. Платформа 1С:Предприятие разграничивает доступ к данным для обеспечения безопасности и целостности информации. Попытка создать или изменить объект на клиенте приведёт к исключению "Объект не найден" или "Нет прав на выполнение операции".

Оптимизация клиентских процедур: советы разработчикам

Клиентский код должен быть не только функциональным, но и оптимизированным — особенно если он выполняется в многопользовательском режиме. Вот несколько рекомендаций:

  1. Минимизируйте обращения к серверу:
    • 📥 Запрашивайте данные пакетами (например, через Выбрать() с ограничением по количеству строк).
    • 🔄 Используйте кэширование часто используемых данных на клиенте (например, справочники с небольшим количеством записей).
  2. Избегайте тяжелых вычислений в основном потоке:
    • ⏳ Для длительных операций (например, генерация отчётов) используйте 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 секунды, рассмотрите оптимизацию.

    Пример отладочного кода для клиентской процедуры:

    &НаКлиенте
    

    Процедура ТестоваяПроцедура()

    Сообщить("Начало выполнения клиентской процедуры", СтатусСообщения.Информация);

    Начало = ТекущаяДата();

    //.. основной код процедуры

    Конец = ТекущаяДата();

    Сообщить("Время выполнения: " + (Конец - Начало) + " мс", СтатусСообщения.Обычное);

    КонецПроцедуры

    Для отладки асинхронных вызовов (например, после ВыполнитьНаКлиенте()) используйте условные точки останова или вывод в журнал, так как стандартный отладчик может не захватывать такие вызовы.

    Если клиентская процедура работает нестабильно в веб-клиенте, проверьте:

    • 🔒 Настройки безопасности браузера (разрешения на выполнение скриптов).
    • 📡 Стабильность интернет-соединения (потери пакетов могут прерывать выполнение).
    • 🛠️ Версию браузера и его совместимость с текущей версией платформы .

    FAQ: Частые вопросы по клиентским процедурам в 1С

    Можно ли из клиентской процедуры обратиться к базе данных напрямую?

    Нет, клиентский код не имеет прямого доступа к базе данных. Для работы с данными необходимо вызывать серверные процедуры через механизмы платформы (например, ВыполнитьНаСервере()). Это правило действует даже если вы работаете в толстом клиенте — платформа жёстко разграничивает контексты выполнения.

    Как передать сложный объект (например, документ) из серверной процедуры в клиентскую?

    Прямая передача ссылок на объекты базы (документов, справочников) в клиентскую процедуру невозможна. Вместо этого передавайте:

    • Идентификаторы объектов (например, Документ.Ссылка.УникальныйИдентификатор()).
    • Сериализуемые данные (строки, числа, структуры, массивы).

    На клиенте можно получить полный объект по идентификатору через вызов серверной процедуры:

    &НаКлиенте
    

    Процедура ПолучитьДокументПоИдентификатору(Ид)

    Документ = ВыполнитьНаСервере("НаСервереПолучитьДокумент", Ид);

    КонецПроцедуры

    &НаСервере

    Функция НаСервереПолучитьДокумент(Ид)

    Возврат Документы.ЗаказКлиента.НайтиПоИдентификатору(Ид);

    КонецФункции

    Почему клиентская процедура работает в толстом клиенте, но не работает в веб-клиенте?

    Это связано с ограничениями веб-клиента:

    • 🚫 Запрещена работа с COMОбъект (например, Excel, Word).
    • 📁 Ограничен доступ к локальной файловой системе (требуется использование диалогов выбора файлов).
    • 🔌 Некоторые API платформы могут быть недоступны или работать иначе.

    Решение: используйте кросс-платформенные методы (например, ЗаписьJSON вместо Excel) или реализуйте альтернативную логику для веб-клиента.

    Как сделать так, чтобы клиентская процедура выполнялась в фоновом режиме?

    В толстом клиенте можно использовать объект BackgroundWorker для выполнения кода в отдельном потоке:

    &НаКлиенте
    

    Процедура ЗапуститьФоновуюЗадачу()

    Работник = Новый BackgroundWorker;

    Работник.ВыполнитьАсинхронно("ФоноваяПроцедура", 10); // Передаём параметр

    КонецПроцедуры

    &НаКлиенте

    Процедура ФоноваяПроцедура(Параметр) Экспорт

    // Код выполняется в фоновом потоке

    Сообщить("Фоновая задача завершена с параметром: " + Параметр);

    КонецПроцедуры

    В тонком и веб-клиенте фоновые задачи не поддерживаются — используйте разбиение длительных операций на части с паузами (Подождать()).

    Можно ли из клиентской процедуры вызвать другую клиентскую процедуру асинхронно?

    Платформа 1С:Предприятие не поддерживает прямые асинхронные вызовы между клиентскими процедурами. Однако можно эмулировать асинхронность:

    • С помощью Подождать() для коротких задержек.
    • Через механизм событий (например, установить флаг и обработать его в основном цикле).
    • В толстом клиенте — с использованием BackgroundWorker.

    Пример с Подождать():

    &НаКлиенте
    

    Процедура АсинхронныйВызов()

    // Запускаем "асинхронно" через небольшую задержку

    Подождать(1); // 1 мс

    ДругаяКлиентскаяПроцедура();

    КонецПроцедуры