Как периодически запускать функцию с параметрами на управляемой форме и получать результат?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

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

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

Суть проблемы и ограничения платформы

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

Основные ограничения, с которыми мы сталкиваемся:

  1. Только процедура: Мы не можем напрямую вызвать функцию.
  2. Без параметров: Процедура-обработчик должна быть определена без аргументов. Если вы попытаетесь указать процедуру с параметрами, платформа выдаст ошибку во время выполнения.
  3. Контекст: Обработчик всегда запускается на стороне клиента.

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

Шаг 1. Создание процедуры-обертки

Поскольку мы не можем изменить поведение платформы, нам необходимо подстроиться под него. Самым эффективным решением, предложенным в обсуждении, является использование паттерна "Обертка" (Wrapper).

Идея проста: мы создаем процедуру без параметров, которая удовлетворяет требованиям метода ПодключитьОбработчикОжидания. Внутри этой процедуры мы вызываем нашу целевую функцию уже с нужными параметрами.

Рассмотрим структуру кода:


&НаКлиенте
Процедура ПриОткрытии()
    // Запускаем обработчик, который будет срабатывать каждые 10 секунд
    ПодключитьОбработчикОжидания("ОбработчикПериодическойЗадачи", 10);
КонецПроцедуры

&НаКлиенте
Процедура ОбработчикПериодическойЗадачи()
    // Это и есть наша "обертка".
    // Здесь мы можем подготовить данные и вызвать нужную функцию
    
    // 1. Получаем параметры (об этом ниже)
    // 2. Вызываем функцию
    ВыполнитьСложныйРасчет();
    
КонецПроцедуры

Шаг 2. Где хранить параметры?

Самый острый вопрос в теме форума: "Откуда взять параметры, если в процедуру их передать нельзя?".

В управляемых формах 1С нет "глобальной памяти" в привычном понимании процедурного программирования, которая была бы доступна везде и всегда без нюансов контекста. Однако у нас есть контекст самой формы. Рассмотрим варианты хранения данных, предложенные участниками обсуждения.

Вариант А: Реквизиты формы (Рекомендуемый)

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

Преимущества:

Реализация:


&НаКлиенте
Процедура ОбработчикПериодическойЗадачи()
    // Параметр берется из реквизита формы Объект или созданного нами реквизита
    ТекущийПараметр = Объект.Склад; 
    
    // Передаем значение в функцию
    Результат = ФункцияРасчета(ТекущийПараметр);
КонецПроцедуры

Вариант Б: Переменные модуля (С ограничениями)

Автор темы спрашивал про использование Перем в шапке модуля. Этот вариант возможен, но имеет существенные недостатки в клиент-серверной архитектуре.

Переменная, объявленная в модуле формы, существует только в том контексте, где она инициализирована. В управляемом приложении переменная модуля на Клиенте будет сохранять значение между вызовами ОбработчикПериодическойЗадачи. Однако, если ваша функция требует обращения к Серверу, эти переменные "невидимы" для сервера, их придется передавать явным параметром.

Шаг 3. Как получить результат функции?

Функции в программировании возвращают значение. Но ПодключитьОбработчикОжидания ничего не ждет в ответ. Куда девать результат?

Здесь мы используем принцип "Побочных эффектов" (Side Effects). Результат выполнения функции должен быть записан во "внешнюю среду" — в элементы формы или реквизиты.

Давайте посмотрим на полный пример реализации, решающий проблему автора.


// Предположим, у нас есть реквизиты формы:
// "ПараметрДляРасчета" (Число) - входные данные
// "РезультатРасчета" (Число) - сюда запишем ответ

&НаКлиенте
Процедура ПриОткрытии()
    // Запускаем цикл
    ПодключитьОбработчикОжидания("ВыполнитьПериодическуюОперацию", 5);
КонецПроцедуры

&НаКлиенте
Процедура ВыполнитьПериодическуюОперацию()
    
    // 1. Считываем текущее состояние (ПАРАМЕТРЫ)
    // Мы берем их из реквизитов формы, которые пользователь мог изменить
    ВходноеЗначение = ЭтотОбъект.ПараметрДляРасчета;
    
    // 2. Вызываем функцию обработки
    НовоеЗначение = ПолучитьДанныеССервера(ВходноеЗначение);
    
    // 3. Сохраняем результат (РЕЗУЛЬТАТ)
    // Записываем данные обратно в форму, чтобы пользователь их увидел
    ЭтотОбъект.РезультатРасчета = НовоеЗначение;
    
КонецПроцедуры

&НаСервереБезКонтекста
Функция ПолучитьДанныеССервера(Знач ВходнойПараметр)
    // Выполняем логику
    Возврат ВходнойПараметр * 2; 
КонецФункции

Сложный случай: Динамические параметры (Очередь)

Иногда задача сложнее: нужно при каждом срабатывании таймера обрабатывать разные данные (например, перебирать массив товаров по одному, чтобы не вешать интерфейс).

В этом случае в реквизите формы можно хранить список (Массив или СписокЗначений). А процедура-обертка будет работать как обработчик очереди.

Давайте разберем алгоритм такого решения:

  1. Создаем реквизит формы ОчередьЗадач (тип Произвольный, при инициализации помещаем туда Массив).
  2. В процедуре-обертке проверяем: если массив пуст — отключаем обработчик.
  3. Если элементы есть — берем первый (или последний), удаляем его из массива и передаем как параметр в функцию.

&НаКлиенте
Процедура ОбработатьОчередь()
    
    // Проверяем наличие задач
    Если ОчередьЗадач.Количество() = 0 Тогда
        ОтключитьОбработчикОжидания("ОбработатьОчередь");
        Возврат;
    КонецЕсли;
    
    // Извлекаем параметр для текущего такта
    ТекущийТовар = ОчередьЗадач[0];
    ОчередьЗадач.Удалить(0);
    
    // Выполняем функцию с параметром
    ОбработатьТовар(ТекущийТовар);
    
КонецПроцедуры

Использование Временного хранилища

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

В обсуждении справедливо упомянули ПоместитьВоВременноеХранилище. В этом случае:

  1. В реквизите формы хранится только строка — Адрес во временном хранилище.
  2. Процедура-обертка передает этот адрес на сервер.
  3. На сервере функция получает данные по адресу через ПолучитьИзВременногоХранилища, обрабатывает их и, при необходимости, помещает результат обратно.

Итоги и рекомендации

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

← На главную