В современной разработке на платформе 1С все чаще используются асинхронные вызовы. Они позволяют выполнять длительные операции без блокировки интерфейса пользователя, что делает программу более отзывчивой. Однако при работе с ними, особенно у начинающих разработчиков, возникает типичная проблема: после завершения асинхронной операции не удается вызвать другую процедуру или функцию формы, и система выдает ошибку "Метод объекта не обнаружен". Разберем, почему это происходит и как правильно организовать код.
Проанализируем ситуацию, с которой столкнулся автор вопроса. Есть клиентская процедура, которая запускает асинхронный вызов, а по его завершении должна выполнить другую процедуру, расположенную на сервере.
Исходный код выглядит примерно так:
Клиентская процедура, запускающая асинхронную операцию:
&НаКлиенте
Процедура ВыполнитьАсинхронно()
ОписаниеОповещения = Новый ОписаниеОповещения("ПослеРасчета", ЭтотОбъект);
Обещание = МойОбщийМодуль.АсинхронныйРасчет();
Обещание.Тогда(ОписаниеОповещения);
КонецПроцедуры
Обработчик, который должен выполниться после завершения обещания:
&НаКлиенте
Процедура ПослеРасчета(Результат, ДополнительныеПараметры) Экспорт
Расчет(); // Вот здесь и возникает ошибка
КонецПроцедуры
Серверная процедура, которую нужно вызвать:
&НаСервере
Процедура Расчет()
// ... какая-то логика на сервере ...
КонецПроцедуры
На первый взгляд, все логично. Мы вызываем процедуру Расчет() из процедуры ПослеРасчета(). Обе они являются частью одной и той же формы. Однако система не может найти метод Расчет().
Причина кроется в контексте выполнения. Когда мы передаем имя процедуры "ПослеРасчета" в ОписаниеОповещения, мы, по сути, передаем "указатель" на нее. После того как асинхронная операция завершается, платформа выполняет эту процедуру-обработчик, но делает это в несколько ином, "оторванном" от формы контексте. В этом новом контексте система "не знает" о других методах формы, таких как Расчет(). Она ищет глобальную процедуру с таким именем, не находит ее и справедливо сообщает об ошибке.
Чтобы решить проблему, нам нужно явно указать платформе, в каком объекте следует искать вызываемый метод. Для этого используется свойство ЭтотОбъект, которое внутри модуля формы (или отчета, обработки) всегда ссылается на сам объект формы.
Исправим код обработчика:
ПослеРасчета.Расчет() напишем ЭтотОбъект.Расчет().Правильный код будет выглядеть так:
&НаКлиенте
Процедура ПослеРасчета(Результат, ДополнительныеПараметры) Экспорт
ЭтотОбъект.Расчет(); // Явно указываем, что метод принадлежит форме
КонецПроцедуры
Теперь, когда обработчик будет вызван, он получит четкую инструкцию: "найди объект, который инициировал этот вызов (ЭтотОбъект), и у него вызови метод Расчет()". Платформа успешно найдет серверную процедуру и выполнит ее. Это самый надежный и универсальный способ для вызова методов формы из асинхронных обработчиков.
Современные версии платформы 1С:Предприятие 8 поддерживают лямбда-выражения. Это позволяет писать более компактный и читаемый код, избавляя от необходимости создавать отдельную экспортную процедуру для обработчика.
Рассмотрим, как можно переписать исходный вызов с использованием лямбды. В этом случае мы передаем в метод .Тогда() не ОписаниеОповещения, а саму анонимную процедуру.
&НаКлиенте
Процедура ВыполнитьАсинхронно()
МойОбщийМодуль.АсинхронныйРасчет().Тогда(
(Результат, ДопПараметры) => ЭтотОбъект.Расчет()
);
КонецПроцедуры
Проанализируем этот код:
ПослеРасчета. Вся логика обработчика описывается прямо в месте вызова.(Результат, ДопПараметры) => ЭтотОбъект.Расчет() — это и есть лямбда-выражение. Оно означает: "создать анонимную процедуру, которая принимает параметры Результат и ДопПараметры, и при ее вызове выполнить код ЭтотОбъект.Расчет()".ЭтотОбъект, так как анонимная процедура выполняется в том же "оторванном" контексте, что и обычный обработчик.Этот подход удобен, когда логика обработчика проста и состоит из одного-двух вызовов. Если же в обработчике нужно выполнить много сложных действий, лучше вынести их в отдельную именованную процедуру для лучшей читаемости кода.
Подведем итоги. При работе с асинхронными операциями в 1С важно помнить о контексте выполнения.
ОписаниеОповещения или метод .Тогда(), выполняется в контексте, отдельном от контекста формы.ЭтотОбъект.ЭтотОбъект.Запомните простое правило: в любом коде, который выполняется асинхронно (в обработчиках .Тогда(), .Иначе(), .Всегда()), при обращении к методам формы всегда используйте префикс ЭтотОбъект.. Это убережет вас от трудноуловимых ошибок и сделает код надежным и предсказуемым.