При переходе на асинхронную модель работы разработчики в 1С часто сталкиваются с трудностями: код, привычный для традиционного синхронного программирования, перестает работать понятным образом. Направляя асинхронный запрос (например, для проверки существования файла или показа диалога), невозможно просто написать оператор Возврат и получить результат в той же точке кода. Выясним причину этого поведения и подробно рассмотрим способы правильной обработки результатов асинхронных операций.
Проанализируем ситуацию. В синхронном коде платформа приостанавливает выполнение текущей функции до тех пор, пока запрашиваемое действие не будет завершено. В асинхронной модели поток исполнения не останавливается: процедура инициирует операцию и моментально завершает свою работу.
Поэтому физически невозможно вернуть результат асинхронной проверки файла в ту же самую процедуру, где был сделан вызов. Вся логика алгоритма должна быть явно разделена на две части:
Рассмотрим традиционный подход, применяемый на управляемых формах. Для перехвата результатов асинхронных операций используется объект ОписаниеОповещения. В него передаются имя процедуры, которая должна выполниться по завершении операции, и модуль (например, ЭтаФорма).
Посмотрим на конкретный пример выбора файла и последующей проверки его существования с помощью асинхронных вызовов:
&НаКлиенте
Процедура ВыбратьФайлСертификата(Команда)
Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
// Запускаем асинхронный показ диалога
ОписаниеОповещенияВыбор = Новый ОписаниеОповещения("ВыбратьФайлСертификатаЗавершение", ЭтаФорма);
Диалог.Показать(ОписаниеОповещенияВыбор);
КонецПроцедуры
&НаКлиенте
Процедура ВыбратьФайлСертификатаЗавершение(ВыбранныеФайлы, ДополнительныеПараметры) Экспорт
Если ВыбранныеФайлы <> Неопределено Тогда
ИмяФайла = ВыбранныеФайлы[0];
ФайлОбъект = Новый Файл(ИмяФайла);
// Передаем имя файла в контексте дополнительных параметров
ОписаниеОповещенияПроверка = Новый ОписаниеОповещения("ПроверитьФайлЗавершение", ЭтаФорма, ИмяФайла);
ФайлОбъект.НачатьПроверкуСуществования(ОписаниеОповещенияПроверка);
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура ПроверитьФайлЗавершение(ФайлСуществует, ИмяФайла) Экспорт
Если ФайлСуществует Тогда
// Продолжение работы: чтение и обработка файла
ОбработатьФайл(ИмяФайла);
Иначе
ПоказатьПредупреждение(, "Указанный файл не найден на диске!");
КонецЕсли;
КонецПроцедуры
Обратите внимание: процедуры-обработчики, указанные в ОписаниеОповещения, обязательно должны содержать директиву Экспорт, иначе платформа не сможет вызвать их из внешнего контекста.
Начиная с версии платформы 8.3.18, появился удобный механизм работы с асинхронным кодом. С помощью модификатора Асинх и ключевого слова Ждать можно писать асинхронный код визуально линейным образом, не разбивая его вручную на множество процедур с оповещениями.
Вместо метода НачатьПроверкуСуществования() используется асинхронный метод СуществуетАсинх(). Разберем по шагам, как это реализовать:
&НаКлиенте
Асинх Функция ФайлСуществуетАсинх(ПутьКФайлу)
ФайлОбъект = Новый Файл(ПутьКФайлу);
// Оператор Ждать приостанавливает выполнение метода до получения ответа
Возврат Ждать ФайлОбъект.СуществуетАсинх();
КонецФункции
&НаКлиенте
Асинх Процедура ОбработатьВыбранныйФайл()
Путь = "C:\temp\data.txt";
// Вызываем асинхронную функцию и ждем результат
РезультатПроверки = Ждать ФайлСуществуетАсинх(Путь);
Если РезультатПроверки Тогда
// Файл существует, продолжаем исполнение
ОбработатьФайл(Путь);
КонецЕсли;
КонецПроцедуры
При проектировании алгоритмов с асинхронными вызовами следует учитывать важные особенности платформы:
Ждать: данный оператор разрешено использовать исключительно внутри процедур и функций, объявленных с модификатором Асинх. Использование его в обычном методе приведет к ошибке компиляции.Асинх Функция всегда возвращает объект типа Обещание. Для извлечения фактического значения из обещания вызывающий код обязан использовать оператор Ждать.Асинх нельзя приостановить снаружи с помощью Ждать, так как она не возвращает Обещание. Если необходимо гарантированно дождаться завершения всей цепочки действий, используйте Асинх Функция.Знач), поэтому изменить значение переменной вызывающего контекста напрямую из асинхронной функции не получится.СуществуетАсинх()) является строго обязательным требованием платформы.