Как правильно вызвать серверный метод из асинхронной операции в 1С?

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

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

Анализ проблемы: почему возникает ошибка?

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

Исходный код выглядит примерно так:

Клиентская процедура, запускающая асинхронную операцию:


&НаКлиенте
Процедура ВыполнитьАсинхронно()
    ОписаниеОповещения = Новый ОписаниеОповещения("ПослеРасчета", ЭтотОбъект);
    Обещание = МойОбщийМодуль.АсинхронныйРасчет();
    Обещание.Тогда(ОписаниеОповещения);
КонецПроцедуры

Обработчик, который должен выполниться после завершения обещания:


&НаКлиенте
Процедура ПослеРасчета(Результат, ДополнительныеПараметры) Экспорт
    Расчет(); // Вот здесь и возникает ошибка
КонецПроцедуры

Серверная процедура, которую нужно вызвать:


&НаСервере
Процедура Расчет()
    // ... какая-то логика на сервере ...
КонецПроцедуры

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

Причина кроется в контексте выполнения. Когда мы передаем имя процедуры "ПослеРасчета" в ОписаниеОповещения, мы, по сути, передаем "указатель" на нее. После того как асинхронная операция завершается, платформа выполняет эту процедуру-обработчик, но делает это в несколько ином, "оторванном" от формы контексте. В этом новом контексте система "не знает" о других методах формы, таких как Расчет(). Она ищет глобальную процедуру с таким именем, не находит ее и справедливо сообщает об ошибке.

Решение 1: Явное указание контекста через "ЭтотОбъект"

Чтобы решить проблему, нам нужно явно указать платформе, в каком объекте следует искать вызываемый метод. Для этого используется свойство ЭтотОбъект, которое внутри модуля формы (или отчета, обработки) всегда ссылается на сам объект формы.

Исправим код обработчика:

  1. Откроем процедуру ПослеРасчета.
  2. Вместо прямого вызова Расчет() напишем ЭтотОбъект.Расчет().

Правильный код будет выглядеть так:


&НаКлиенте
Процедура ПослеРасчета(Результат, ДополнительныеПараметры) Экспорт
    ЭтотОбъект.Расчет(); // Явно указываем, что метод принадлежит форме
КонецПроцедуры

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

Решение 2: Использование лямбда-выражений (анонимных процедур)

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

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


&НаКлиенте
Процедура ВыполнитьАсинхронно()
    МойОбщийМодуль.АсинхронныйРасчет().Тогда(
        (Результат, ДопПараметры) => ЭтотОбъект.Расчет()
    );
КонецПроцедуры

Проанализируем этот код:

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

Ключевые выводы

Подведем итоги. При работе с асинхронными операциями в 1С важно помнить о контексте выполнения.

  1. Процедура-обработчик, передаваемая в ОписаниеОповещения или метод .Тогда(), выполняется в контексте, отдельном от контекста формы.
  2. Для вызова процедур или функций самой формы (серверных или клиентских) из такого обработчика необходимо всегда явно указывать объект, которому принадлежит метод. Делается это через ЭтотОбъект.
  3. Использование лямбда-выражений может значительно сократить код, но не отменяет необходимости указывать контекст через ЭтотОбъект.

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

← На главную