"Promises, promises" группы Naked eyes
Я уверен, что именно эта песня играла, когда выбирался подход для реализации асинхронности в 1С.
Распространённое заблуждение - смешивание понятий асинхронных процедур и функций и многопоточности. Вот реализация асинхронных процедур:
&НаКлиенте
Асинх Процедура КопируемыйФайлНачалоВыбора(Элемент, ДанныеВыбора, СтандартнаяОбработка)
Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
Обещание = Диалог.ВыбратьАсинх();
Попытка
Результат = Ждать Обещание;
Если ТипЗнч(Результат) = Тип("Массив") И Результат.Количество() Тогда
КопируемыйФайл = Результат[0];
Иначе
Возврат;
КонецЕсли;
Исключение
Сообщить(ИнформацияОбОшибке().Описание);
КонецПопытки;
КонецПроцедуры
&НаКлиенте
Асинх Процедура ЗапуститьКопированиеФайла(Команда)
ИмяКопируемогоФайла = РазложитьПолноеИмяФайла(КопируемыйФайл).Имя;
ОбещаниеСкопироватьФайл = КопироватьФайлАсинх(КопируемыйФайл, Каталог + "\"+ ИмяКопируемогоФайла);
ОбещаниеПредупреждения = ПредупреждениеАсинх("Файл копируется.", 1);
Попытка
Ждать ОбещаниеСкопироватьФайл;
Исключение
Ждать ОбещаниеПредупреждения;
Сообщить(ОписаниеОшибки());
Возврат;
КонецПопытки;
Ждать ОбещаниеПредупреждения;
ПредупреждениеАсинх("Файл скопирован.");
КонецПроцедуры
Асинхронность проще воспринимать как нарезанный хлеб, который вы положили под матрас и ушли по своим делам, а когда захотели сухарей, то заглянули под него. С одним лишь отличием, что в этом матрасе есть вложенные матрасы :) Для многопоточной работы на клиенте мы можем использовать объект встроенного языка "Поток", доступный на клиенте:
&НаКлиенте
Асинх Процедура ЗапуститьКопированиеФайла(Команда)
ИмяКопируемогоФайла = РазложитьПолноеИмяФайла(КопируемыйФайл).Имя;
ИсполняемыйКодПотокаКопирования = "Ждать КопироватьФайлАсинх(КопируемыйФайл, Каталог + ""\""+ ИмяКопируемогоФайла)";
Идентификатор = Новый УникальныйИдентификатор();
ИдентификаторОбещанияПотокаКопирования = Новый Поток(ИсполняемыйКодПотокаКопирования,Идентификатор);
//Какой-то код.
//А тут нам точно нужен результат.
Пока НЕ(ОбещаниеПотокаИсполнено(ИдентификаторОбещанияПотокаКопирования)) Цикл
КонецЦикла;
Результат = ОбещаниеПотока(ИдентификаторОбещанияПотокаКопирования);
Если НЕ(ТипЗнч(Результат) = Тип("Исключение")) Тогда
ПолноеИмяСкопированногоФайла = Результат.ОбещаниеПотока;
Иначе
ВызватьИсключениеАсинх(Результат);
КонецЕсли;
КонецПроцедуры
На сервере для реализации многопоточности можно использовать связку из фоновых заданий и оповещений. Лучше использовать БСП. Для этого в форме напишем следующий код в форме:
&НаКлиенте
Процедура УвеличитьПоЧислуФоновыхЗаданий(Команда)
СброситьСчётчикНаСервере();
ФоновоеЗадание = УвеличитьПоЧислуФоновыхЗаданийНаСервере();
ОповещениеОПрогрессеВыполнения = Новый ОписаниеОповещения("ПрогрессВыполнения", ЭтотОбъект);
НастройкиОжидания = ДлительныеОперацииКлиент.ПараметрыОжидания(ЭтотОбъект);
НастройкиОжидания.ВыводитьОкноОжидания = Ложь;
НастройкиОжидания.ОповещениеОПрогрессеВыполнения = ОповещениеОПрогрессеВыполнения;
Обработчик = Новый ОписаниеОповещения("ПослеЗаписиЗагружаемыхДанныхОтчет", ЭтотОбъект);
ДлительныеОперацииКлиент.ОжидатьЗавершение(ФоновоеЗадание, Обработчик, НастройкиОжидания);
КонецПроцедуры
&НаСервере
Функция УвеличитьПоЧислуФоновыхЗаданийНаСервере()
ФЗ = ВыполнитьПроцедуруМногопоточно();
Возврат ФЗ;
КонецФункции
&НаСервере
Функция ВыполнитьПроцедуруМногопоточно()
ПараметрыВыполнения = ДлительныеОперации.ПараметрыВыполненияВФоне(ЭтаФорма.УникальныйИдентификатор);
ПараметрыВыполнения.НаименованиеФоновогоЗадания = НСтр("ru = 'ТестированиеМногопоточности'");
ПараметрыВыполнения.ЗапуститьВФоне = Истина;
ПараметрыМетода = Новый Соответствие();
Для Итератор = 1 По ЧислоФоновыхЗаданий Цикл
МассивИтераторов = НОвый Массив();
МассивИтераторов.Добавить(Итератор);
//ключ-не важен, параметры по порядку
ПараметрыМетода.Вставить("ЗадержкаСекунд" + Итератор, МассивИтераторов);
КонецЦикла;
ФоновоеЗадание = ДлительныеОперации.ВыполнитьПроцедуруВНесколькоПотоков("ТестированиеСчетчика.ИнкрементироватьАсинх",
ПараметрыВыполнения, ПараметрыМетода);
Возврат ФоновоеЗадание;
КонецФункции
&НаКлиенте
Процедура ПослеЗаписиЗагружаемыхДанныхОтчет(ФоновоеЗадание, ДополнительныеПараметры) Экспорт
Если ФоновоеЗадание = Неопределено Тогда
Возврат;
КонецЕсли;
Если ФоновоеЗадание.Статус = "Выполнено" Тогда
КонецЕсли;
Если ФоновоеЗадание.Статус = "Ошибка" Тогда
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура ПрогрессВыполнения(Результат, ДополнительныеПараметры) Экспорт
Если Результат.Статус = "Выполняется" Тогда
Прогресс = ПрочитатьПрогресс(Результат.ИдентификаторЗадания);
Если Прогресс <> Неопределено Тогда
СчетчикВыполнения = СчетчикВыполнения + Число(Прогресс.Текст);
Сообщить(СчетчикВыполнения);
КонецЕсли;
КонецЕсли;
КонецПроцедуры
&НаСервереБезКонтекста
Функция ПрочитатьПрогресс(ИдентификаторЗадания)
Возврат ДлительныеОперации.ПрочитатьПрогресс(ИдентификаторЗадания);
КонецФункции
И в общем модуле:
Процедура ИнкрементироватьАсинх(ЗадержкаСекунд) Экспорт
Если ЗадержкаСекунд > 5 Тогда
ЗадержкаСекунд = 1;
КонецЕсли;
Генератор = НОвый ГенераторСлучайныхЧисел;
apПауза.ВыполнитьПаузу_ВСекундах(1,"Тестовая пауза");
ДлительныеОперации.СообщитьПрогресс(0,
1);
КонецПроцедуры
Осталось подождать, чтобы объект "Поток" перестал быть плодом воображения, Всем отличного дня!