В практике разработки на платформе 1С:Предприятие 8.3 программисты часто сталкиваются с ситуацией, когда после выполнения серверной процедуры стандартный метод Закрыть(), вызванный на клиенте, попросту игнорируется. Форма остается открытой, хотя весь код, казалось бы, написан верно. Особенно часто эта проблема проявляется при работе с внешними обработками, подключенными через механизм "Дополнительные отчеты и обработки". Рассмотрим подробно причины такого поведения и разберем пошагово методы диагностики и решения проблемы.
Проанализируем типичный сценарий: у нас есть команда формы, которая должна выполнить обработку данных на сервере и затем закрыть окно. Стандартная реализация выглядит следующим образом:
&НаКлиенте
Процедура ВыполнитьДействие(Команда)
// Вызов серверной процедуры для обработки данных
ВыполнитьДействиеНаСервере();
// Попытка закрыть форму после завершения работы на сервере
ЭтаФорма.Закрыть();
КонецПроцедуры
&НаСервере
Процедура ВыполнитьДействиеНаСервере()
// Пример логики: изменение реквизитов объектов
Для каждого Ссылка Из Объект.СписокОбъектов Цикл
ОбъектСправ = Ссылка.ПолучитьОбъект();
ОбъектСправ.СтавкаНДС = Объект.НоваяСтавкаНДС;
ОбъектСправ.Записать();
КонецЦикла;
КонецПроцедуры
На первый взгляд, код абсолютно корректен. Однако, если после вызова ВыполнитьДействиеНаСервере() управление не возвращается в клиентский поток должным образом или происходит "тихое" прерывание, команда Закрыть() не будет выполнена. Выясним основные причины, почему это происходит.
Когда мы используем внешнюю обработку через справочник "Дополнительные отчеты и обработки", платформа копирует файл обработки во временный каталог пользователя. Если вы внесли изменения в код (например, добавили команду Закрыть()), но не обновили файл в справочнике или платформа продолжает открывать старую версию из локального кэша, изменения не вступят в силу.
Рассмотрим алгоритм действий для исключения влияния кэша:
%TEMP%) и кэш конфигурации 1С.Если внутри серверного цикла происходит ошибка (например, объект заблокирован другим пользователем или не заполнен обязательный реквизит), и эта ошибка не обернута в блок Попытка...Исключение, выполнение кода прерывается. В некоторых контекстах (особенно в дополнительных обработках) это приводит к тому, что клиентский код, следующий за серверным вызовом, просто не запускается.
Проанализируем ситуацию и добавим безопасную обработку ошибок:
&НаКлиенте
Процедура УстановитьНДС(Команда)
Попытка
УстановитьНДСНаСервере();
// Если сервер отработал успешно, закрываем форму
Закрыть();
Исключение
// Сообщаем пользователю о проблеме, форма остается открытой для анализа
ТекстОшибки = КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
ОбщегоНазначенияКлиентСервер.СообщитьПользователю("Ошибка при выполнении: " + ТекстОшибки);
КонецПопытки;
КонецПроцедуры
Использование метода ОбщегоНазначенияКлиентСервер.СообщитьПользователю (из состава БСП) позволяет гарантированно вывести текст ошибки, даже если стандартное системное окно сообщения блокируется контекстом выполнения.
В версиях платформы 8.3.27.1719 и смежных были зафиксированы случаи некорректного поведения механизма возврата управления с сервера на клиент. Проблема часто проявляется в том, что после длительной серверной операции клиентские методы (Закрыть(), Сообщить(), Вопрос()) игнорируются. Это связано с внутренней синхронизацией потоков платформы.
Посмотрим на способы обхода этой проблемы:
Пример использования отложенного закрытия:
&НаКлиенте
Процедура ЗавершитьРаботуАсинхронно()
Закрыть();
КонецПроцедуры
&НаКлиенте
Процедура ВыполнитьИЗакрыть(Команда)
ВыполнитьНаСервере();
// Подключаем однократный обработчик ожидания на 0.1 секунды
ПодключитьОбработчикОжидания("ЗавершитьРаботуАсинхронно", 0.1, Истина);
КонецПроцедуры
Такой подход позволяет платформе полностью завершить текущий сеанс связи с сервером и корректно обработать очередь клиентских событий.
Если отладка внешней обработки затруднена (например, она запущена в составе БСП), воспользуемся методом Сообщить(). Важно расставить контрольные точки до и после серверного вызова:
&НаКлиенте
Процедура ТестЗакрытия(Команда)
Сообщить("Начало выполнения...");
УстановитьНДСНаСервере();
Сообщить("Вернулись с сервера!");
Закрыть();
Сообщить("Команда Закрыть отправлена");
КонецПроцедуры
Если в окне сообщений вы видите "Начало выполнения...", но не видите "Вернулись с сервера!", значит, проблема локализована внутри серверной процедуры (происходит зависание или критическая ошибка). Если же вы видите все сообщения, но форма висит — это прямое указание на баг платформы или блокировку интерфейса модальным окном/владельцем формы.
Важный момент для Розницы 2.3 и других конфигураций на БСП: При программном изменении объектов на сервере рекомендуется использовать метод Оповестить("Записан_Объект", Параметры, ЭтаФорма). Это позволит другим открытым формам (например, списку номенклатуры) узнать об изменениях и обновить данные после того, как ваша обработка закроется.
Для решения проблемы с закрытием формы выполните следующие действия в указанном порядке:
Попытка...Исключение.ПодключитьОбработчикОжидания для разнесения серверного вызова и закрытия формы во времени.