При разработке на платформе 1С:Предприятие 8.2 и 8.3 программисты часто сталкиваются с ограничением стандартного метода ПодключитьОбработчикОжидания. Суть проблемы заключается в том, что в качестве первого параметра метод принимает только имя процедуры в виде строки, и эта процедура, согласно синтаксису платформы, не должна иметь параметров. Если попытаться передать параметры напрямую, например, написав ПодключитьОбработчикОжидания("МояПроцедура(Параметр)", 60), система выдаст ошибку "Недопустимое значение параметра".
В этой статье мы разберем, как элегантно обойти это ограничение, рассмотрим несколько надежных способов передачи данных в обработчик и научимся правильно управлять жизненным циклом таких процедур.
Прежде чем переходить к решениям, выясним причину, по которой 1С накладывает такие ограничения. Метод ПодключитьОбработчикОжидания регистрирует в оперативной памяти клиента задание на выполнение кода через определенный интервал. Платформа ожидает найти процедуру по ее имени в контексте модуля, где был вызван метод (или в глобальном контексте), и вызывает ее без передачи каких-либо аргументов.
Важные правила, которые нужно запомнить:
Экспорт.&НаКлиенте).Рассмотрим ситуацию, когда нам нужно передать значение переменной КоличествоЗаписей в периодическую проверку. Самый простой и эффективный способ — использовать переменную модуля, которая будет доступна и процедуре инициализации, и самой процедуре обработчика.
Проанализируем пример реализации в модуле управляемого приложения:
Перем глДанныеДляОбработчика Экспорт;
&НаКлиенте
Процедура ПриНачалеРаботыСистемы()
// Инициализируем данные, которые хотим "передать"
глДанныеДляОбработчика = Новый Структура;
глДанныеДляОбработчика.Вставить("КоличествоЗаписей", 10);
глДанныеДляОбработчика.Вставить("ВремяНачала", ТекущаяДата());
// Подключаем обработчик. Обратите внимание: скобки не указываем!
ПодключитьОбработчикОжидания("ОбработчикНапоминаний", 60);
КонецПроцедуры
&НаКлиенте
Процедура ОбработчикНапоминаний() Экспорт
// Получаем наши данные из глобальной переменной
Количество = глДанныеДляОбработчика.КоличествоЗаписей;
// Выполняем полезную работу
Если Количество > 0 Тогда
Сообщить("У вас есть активные напоминания: " + Количество);
КонецЕсли;
КонецПроцедуры
В данном примере мы использовали Структура, что является хорошим тоном, так как это позволяет передавать неограниченное количество параметров внутри одного объекта.
Если логика обработки сложная и вы не хотите загромождать модуль управляемого приложения, можно вынести данные в Общий модуль. Для этого создайте общий модуль (например, РаботаСКлиентомГлобальный), установите у него свойства "Клиент (управляемое приложение)" и "Глобальный".
Разберем, как это будет выглядеть в коде:
// В Глобальном общем модуле:
Перем КонтекстОбработчика Экспорт;
Процедура ЗапуститьМониторинг(Параметры) Экспорт
КонтекстОбработчика = Параметры;
ПодключитьОбработчикОжидания("ВыполнитьПроверкуДанных", 30);
КонецПроцедуры
Процедура ВыполнитьПроверкуДанных() Экспорт
// Доступ к КонтекстОбработчика
Если КонтекстОбработчика.УсловиеВыполнено Тогда
// Логика
КонецЕсли;
КонецПроцедуры
Этот метод позволяет инкапсулировать логику и не "мусорить" в основных модулях системы.
Иногда возникает вопрос: можно ли использовать ПараметрыСеанса? Посмотрим на ситуацию критически. Параметры сеанса живут на сервере. Если ваш обработчик ожидания (который работает на клиенте) будет каждую минуту обращаться к параметрам сеанса, это вызовет постоянные серверные вызовы.
Рекомендация: Используйте параметры сеанса только в том случае, если данные должны быть синхронизированы между разными сеансами или если обработчик в любом случае обращается к серверу для получения данных. В остальных случаях лучше хранить данные в локальной памяти клиента.
Часто требуется запускать обработчик не для всех, а только при выполнении определенных условий (например, для пользователей, зашедших в систему после 8:00). Выясним, как это реализовать.
&НаКлиенте
Процедура ПриНачалеРаботыСистемы()
ВремяВхода = ТекущаяДата();
ГраницаВремени = НачалоДня(ВремяВхода) + 8 * 3600; // 8:00 утра
Если ВремяВхода > ГраницаВремени Тогда
ПодключитьОбработчикОжидания("ОбработчикДляОпоздавших", 300);
КонецЕсли;
КонецПроцедуры
Проанализируем важный аспект стабильности. Если внутри обработчика ожидания произойдет ошибка, выполнение кода прервется. Более того, в некоторых версиях платформы это может привести к постоянному появлению окна с ошибкой каждые N секунд, что сделает работу пользователя невозможной.
Всегда оборачивайте код обработчика в блок попытки:
&НаКлиенте
Процедура ОбработчикНапоминаний() Экспорт
Попытка
// Основная логика
ОткрытьФорму("Отчет.МойОтчет.Форма");
Исключение
// Записываем ошибку в журнал регистрации, чтобы не пугать пользователя
ЗаписьЖурналаРегистрации("ОшибкаОбработчика", УровеньЖурналаРегистрации.Ошибка,,, ОписаниеОшибки());
// Можно отключить обработчик, если произошла критическая ошибка
ОтключитьОбработчикОжидания("ОбработчикНапоминаний");
КонецПопытки;
КонецПроцедуры
Если вы подключаете обработчик внутри конкретной формы объекта или списка, помните о правиле: "Уходя, гасите свет". Если форма закроется, а обработчик останется активным, он попытается обратиться к методам формы, которой больше нет в памяти, что вызовет аварийное завершение.
Рассмотрим правильный алгоритм работы в форме:
ПриОткрытии подключаем обработчик.ПриЗакрытии обязательно вызываем ОтключитьОбработчикОжидания("ИмяПроцедуры").Такой подход гарантирует отсутствие "утечек" памяти и стабильную работу приложения.
Несмотря на то, что метод ПодключитьОбработчикОжидания не поддерживает прямую передачу аргументов, использование экспортных переменных в модуле управляемого приложения или глобальных структур полностью решает эту задачу. Главное — следить за тем, чтобы процедура была доступна на клиенте и не забывать про обработку исключительных ситуаций.