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