Заметки из Зазеркалья

20.04.2020

Улучшения в синтаксисе языка 1С для работы с асинхронными функциями: синхронная асинхронность

Данная статья является анонсом новой функциональности.
Не рекомендуется использовать содержание данной статьи для освоения новой функциональности.
Полное описание новой функциональности будет приведено в документации к соответствующей версии.
Полный список изменений в новой версии приводится в файле v8Update.htm.

Планируется в версии 8.3.18 Пробовать

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

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

Наиболее близким аналогом того, что добавлено по части асинхронности в 1С:Предприятие, является тип Promise и конструкции async/await языка JavaScript,  введенные в стандартах ECMAScript 6 и ECMASript 2017, соответственно.

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

Далее будут рассмотрены составные части новой механики, а кроме того некоторые особенности и типовые приемы.

Составные части

Можно сказать, что новая форма работы с асинхронностью включает три составные части:

  • Тип Promise/Обещание
  • «Новые» асинхронные функции платформы, возвращающие Обещание
  • Конструкции Асинх/Async и Ждать/Await во встроенном языке

Рассмотрим эти составляющие.

Тип Promise/Обещание

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

У асинхронной функции, как и у любой другой функции, могут быть два варианта завершения:

  • Нормальное завершение
  • Исключение

В соответствии с этим объект типа Обещание может находиться в одном из трех состояний:

  • Pending – асинхронная функция еще не завершилась, результат еще не определен. Это состояние является начальным для объектов Обещание.
  • Success – функция завершилась успешно. В результате Обещание становится контейнером значения, которое вернула асинхронная функция
  • Failure – при выполнении асинхронной функции было выброшено исключение, не перехваченное внутри функции. И Обещание становится контейнером для этого исключения.

Практически любое Обещание начинает свое существование в состоянии Pending. Затем, в зависимости от того, как завершится асинхронная функция, Обещание может перейти в состояние Success или Failure. И, если Обещание перешло в состояние Success или Failure, то в этом состоянии оно и останется до конца жизни.

Обещание является возвращаемым значением у «новых» асинхронных функций. Как правило, асинхронная функция возвращает Обещание, еще до того, как её выполнение будет фактически завершено. То есть, это Обещание находится в состоянии Pending.

На настоящий момент Обещание ни имеет конструкторов, методов и свойств, доступных из встроенного языка. То есть, новый объект Обещание может появиться только в результате вызова асинхронной функции. А всё, что можно сделать с объектом типа Обещание – это использовать его в качестве аргумента оператора Ждать.

В остальном Обещание является вполне обычным типом. И со значением типа Обещание можно делать то же, что и с любым другим значением - присваивать переменным, передавать в качестве значения параметра процедурам/функциям и т. п.

«Новые» асинхронные функции платформы

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

В дальнейшем ранее существовавшие асинхронные процедуры будем называть «старыми» асинхронными процедурами, а добавленные асинхронные функции, возвращающие Обещание, будем называть «новыми» асинхронными функциями.

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

«Новые» асинхронные функции платформы не имеют параметра <ОписаниеОповещения>, но вместо этого возвращают Обещание, являющееся оберткой для результата выполнения асинхронной функции. И то, как вызывающий код обойдется с этим возвращаемым значением, целиком относится на усмотрение вызывающего кода.

У «старых» асинхронных процедур зачастую имелись прототипы в виде синхронных процедур или функций, на основании которых они были созданы.

Рассмотрим на примере.

В платформе 1С:Предприятие 8 имеется синхронная функция КопироватьФайл (СоpyFile), описание которой выглядит следующим образом:

КопироватьФайл(<ИмяФайлаИсточника>, <ИмяФайлаПриемника>)

Параметры:

  • <ИмяФайлаИсточника> (обязательный)
    Тип: Строка
    Полное имя файла источника
  • <ИмяФайлаПриемника> (обязательный)
    Тип: Строка
    Полное имя файла источника

Данный метод доступен повсеместно. Но на клиенте использование синхронных методов может быть запрещено. Начиная с версии 8.3.6, в платформе появилась асинхронная процедура НачатьКопированиеФайла (BeginCopyingFile) со следующим описанием:

НачатьКопированиеФайла(<ОписаниеОповещения>, <ИмяФайлаИсточника>, <ИмяФайлаПриемника>)

Параметры:

  • <ОписаниеОповещения> (обязательный)
    Тип: ОписаниеОповещения
    Содержит описание процедуры, которая будет вызвана после завершения со следующими параметрами:
    • <СкопированныйФайл> - строка, содержащая путь к скопированному файлу
    • <ДополнительныеПараметры> - значение, которое было указано при создании объекта ОписаниеОповещения
  • <ИмяФайлаИсточника> (обязательный)
    Тип: Строка
    Полное имя файла источника
  • <ИмяФайлаПриемника> (обязательный)
    Тип: Строка
    Полное имя файла источника

И, наконец, в версии 8.3.18 добавляется «новая» асинхронная функция КопироватьФайлАсинх / CopyFileAsync):

КопироватьФайлАсинх(<ИмяФайлаИсточника>, <ИмяФайлаПриемника>)

Параметры:

  • <ИмяФайлаИсточника> (обязательный)
    Тип: Строка
    Полное имя файла источника
  • <ИмяФайлаПриемника> (обязательный)
    Тип: Строка
    Полное имя файла источника

Возвращаемое значение:

  • Тип: Обещание

После успешного завершения копирования файла Обещание будет содержать путь к скопированному файлу. В случае ошибки Обещание будет содержать исключение.

На приведенном примере заметно, что по ряду признаков «новая» асинхронная функция имеет больше сходства с синхронным аналогом, чем со «старой» асинхронной процедурой. В частности, у «новой» асинхронной функции тот же список параметров, что и у синхронной процедуры. Да и имя новой асинхронной процедуры образовано простым добавлением суффикса Асинх / Async к имени синхронной процедуры.

Со «старой» асинхронной процедурой «новую» асинхронную функцию роднит то, что она тоже выполняется асинхронно. А также то, что Обещание при успешном завершении получает то же значение, что и первый параметр процедуры, представляемой объектом ОписаниеОповещения.

У некоторых «старых» асинхронных процедур ОписаниеОповещения должно содержать описание процедуры с единственным параметром <ДополнительныеПараметры>. В этом случае у добавленной «новой» асинхронной функции при успешном завершении Обещание будет всегда содержать Неопределено.

Асинх и Ждать

И, наконец, вершина всей конструкции – это Асинх и Ждать.

Асинх / Async представляет собой модификатор, который может применяться к процедуре или функции, написанной на встроенном языке. Использование данного модификатора делает процедуру или функцию асинхронной. Важной особенностью является также то, что оператор Ждать может использоваться только внутри Асинх процедур/функций.

Аргументом оператора Ждать / Await является Обещание. Логически, оператор Ждать выполняет ожидание завершения асинхронной функции, стоящей за объектом Обещание. При нормальном завершении функции результатом оператора является значение,  которое вернула асинхронная функция. Если же внутри функции было выброшено исключение, то это же исключение вылетает из оператора Ждать.

Таким образом, в результате выполнения

Рез = Ждать Об; // Об имеет тип Обещание

может получиться одно из двух:

  • Переменной Рез будет присвоено значение, которое оказалось завернутым в Обещание в результате нормального завершения асинхронной функции.
  • Оператор Ждать выбросит исключение, которое было выброшено внутри асинхронной функции и оказалось завернутым в Обещание.

Рассмотрим некоторые особенности Асинх процедур и функций.

Передача параметров по значению

Все параметры Асинх процедур и функций передаются только по значению. В обычных процедурах и функциях для передачи параметра по значению перед его именем должно присутствовать ключевое слово Знач. В Асинх процедурах и функциях передача по значению происходит по умолчанию и является единственно возможным вариантом. Наличие или отсутствие ключевого слова Знач не имеет значения.

Таким образом, заголовки функции

Асинх Функция КопироватьФайлыАсинх(ИсхКаталог, ЦелКаталог)

и

Асинх Функция КопироватьФайлыАсинх(Знач ИсхКаталог, Знач ЦелКаталог)

полностью эквивалентны.

Асинх Функция всегда возвращает Обещание

Асинх функция всегда возвращает Обещание. При успешном завершении в Обещание будет завернуто значение, которое было аргументом оператора Возврат. Если при выполнении Асинх функции произошло исключение, то в Обещание будет завернуто это исключение.

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

Процедура П()
Попытка
Функ1();
Исключение
// Исключение из Функ1() не будет перехвачено здесь
КонецПопытки
КонецПроцедуры

Асинх Функция Функ1()
ВызватьИсключение "Выброшено в Функ1()";
КонецФункции

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

Асинх Процедура П()
Попытка
  Ждать НеNull(Null);
Исключение
  // Исключение из НеNull() будет перехвачено здесь
  Сообщить("Передали Null");
КонецПопытки
КонецПроцедуры

Асинх Функция НеNull(П)
  Если П = Null Тогда
    ВызватьИсключение "Выброшено в Функ1()";
  Иначе
    Возврат П;
  КонецЕсли;
КонецФункции

Асинх Процедура ничего не возвращает

Асинх процедура – это в первую очередь процедура, а потом уже Асинх. Как процедура она не возвращает значения. А если при выполнении Асинх процедуры возникнет не перехваченное исключение, то это приведет к выдаче пользователю сообщения об ошибке. Само это исключение никак не может быть перехвачено и обработано вызвавшим процедуру кодом.

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

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

Пример применения

Теперь посмотрим, как использование новых возможностей работы с асинхронностью может выглядеть на практике. Представим, что нам надо разработать форму для копирования файлов из одного каталога на клиентском компьютере в другой. Для простоты полагаем, что копироваться должны только файлы, непосредственно находящиеся в исходном каталоге. Для хранения и редактирования путей к каталогам форма включает два реквизита типа Строка: ИсходныйКаталог и ЦелевойКаталог. Выполнение копирования вызывается командой КопироватьФайлы.

Для начала напишем модуль формы с использованием синхронных методов платформы, в расчете на то, что использование синхронных методов на клиенте не запрещено.

&НаКлиенте
Процедура КопироватьФайлы(Команда)
Попытка
КопироватьФайлыСинх(ИсходныйКаталог, ЦелевойКаталог);
Исключение
Инф = ИнформацияОбОшибке();
ПредупреждениеАсинх("Произошла ошибка: " + Инф.Описание);
КонецПопытки
КонецПроцедуры

&НаКлиенте
Процедура КопироватьФайлыСинх(ИсхКаталог, ЦелКаталог)
Файлы = НайтиФайлы(ИсхКаталог, "*", Ложь);
Для Каждого Файл Из Файлы Цикл
ИсхФайл = ИсхКаталог + "/" + Файл.Имя;
ЦелФайл = ЦелКаталог + "/" + Файл.Имя;
КопироватьФайл(ИсхФайл, ЦелФайл);
КонецЦикла;
КонецФункции

В приведенном фрагменте модуля процедура КопироватьФайлы() является обработчиком команды КопироватьФайлы. Само копирование файлов выполняется процедурой КопироватьФайлыСинх(). Для поиска копируемых файлов используется синхронная функция платформы НайтиФайлы(), а для копирования каждого из найденных файлов – процедура платформы КопироватьФайл(). В процедуре КопироватьФайлы() производится перехват и обработка исключений, которые могут вылететь из КопироватьФайлыСинх().

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

&НаКлиенте
Асинх Процедура КопироватьФайлы(Команда)
Попытка
Ждать КопироватьФайлыАсинх(ИсходныйКаталог, ЦелевойКаталог); //1
Исключение
Инф = ИнформацияОбОшибке();
ПредупреждениеАсинх("Произошла ошибка: " + Инф.Описание);
КонецПопытки
КонецПроцедуры

&НаКлиенте
Асинх Функция КопироватьФайлыАсинх(ИсхКаталог, ЦелКаталог)
Файлы = Ждать НайтиФайлыАсинх(ИсхКаталог, "*", Ложь); //2
Для Каждого Файл Из Файлы Цикл
ИсхФайл = ИсхКаталог + "/" + Файл.Имя;
ЦелФайл = ЦелКаталог + "/" + Файл.Имя;
Ждать КопироватьФайлАсинх(ИсхФайл, ЦелФайл); //3
КонецЦикла;
КонецФункции

Внешнее сходство между «синхронным» и «асинхронным» модулями трудно не заметить. Сосредоточимся на различиях. В асинхронном варианте фактическое копирование файлов выполняет

Асинх Функция КопироватьФайлыАсинх(ИсхКаталог, ЦелКаталог)

То, что в «синхронном» варианте было процедурой, стало Асинх функцией. Появление модификатора Асинх обусловлено тем, что внутри функции вызываются новые асинхронные функции платформы НайтиФайлыАсинх>() и КопироватьФайлАсинх(), а возвращаемые ими значения используются как аргументы операторов Ждать.

Превращение процедуры в функцию объясняется тем, что в процедуре КопироватьФайлы() необходимо перехватить и обработать исключения, которые могут возникнуть при выполнении КопироватьФайлыАсинх().

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

Поэтому при нормальном завершении КопироватьФайлыАсинх() в Обещание во всех случаях окажется завернутым Неопределено, на что указывает отсутствие явного возврата значения в КопироватьФайлыАсинх(). А в процедуре КопироватьФайлы() результат вычисления выражения

Ждать КопироватьФайлыАсинх(ИсходныйКаталог, ЦелевойКаталог); //1

никуда не присваивается. Но при этом сам этот оператор находится внутри блока Попытка…Исключение для того, чтобы перехватить исключение которое может быть выброшено внутри КопироватьФайлыАсинх().

В ходе выполнения

Файлы = Ждать НайтиФайлыАсинх(ИсхКаталог, "*", Ложь); //2

Обещание, которое вернулось из «новой» асинхронной функции платформы НайтиФайлыАсинх(), попадет на вход оператора Ждать. И, после завершения выполнения НайтиФайлыАсинх() в переменную Файлы будет помещен результат поиска файлов или же оператор Ждать выбросит исключение, если в ходе выполнения НайтиФайлыАсинх() произошла ошибка.

Результат вычисления

Ждать КопироватьФайлАсинх(ИсхФайл, ЦелФайл); //3

также никуда не присваивается. В данной точке кода надо просто дождаться завершения копирования файла и выбросить исключение, если при выполнении КопироватьФайлАсинх() произошла ошибка.

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

Усовершенствованный модуль формы может выглядеть следующим образом:

&НаКлиенте
Асинх Процедура КопироватьФайлы(Команда)
Попытка
Сч = Ждать КопироватьФайлыАсинх(ИсходныйКаталог, ЦелевойКаталог); //1
Сообщить("Скопировано файлов: " + Сч);
Исключение
Инф = ИнформацияОбОшибке();
ПредупреждениеАсинх("Произошла ошибка: " + Инф.Описание);
КонецПопытки
КонецПроцедуры

&НаКлиенте
Асинх Функция КопироватьФайлыАсинх(ИсхКаталог, ЦелКаталог)
Файлы = Ждать НайтиФайлыАсинх(ИсхКаталог, "*", Ложь); //2
Счетчик = 0;
Для Каждого Файл Из Файлы Цикл
ИсхФайл = ИсхКаталог + "/" + Файл.Имя;
ЦелФайл = ЦелКаталог + "/" + Файл.Имя;
Ждать КопироватьФайлАсинх(ИсхФайл, ЦелФайл); //3
Счетчик = Счетчик + 1;
КонецЦикла;
Возврат Счетчик;
КонецФункции

Что изменилось?

В функции КопироватьФайлыАсинх() появилась локальная переменная Счетчик для подсчета числа скопированных файлов. Значение этой переменной в явном виде возвращается из функции.

В процедуре КопироватьФайлы() результат оператора Ждать теперь присваивается локальной переменной Сч, значение которой используется при выводе сообщения пользователю.

И, наконец, мы можем упростить процедуру КопироватьФайлы(), если в этой процедуре не требуется специфическая обработка исключений и достаточно просто выдачи сообщения пользователю.

&НаКлиенте
Асинх Процедура КопироватьФайлы(Команда)
Сч = Ждать КопироватьФайлыАсинх(ИсходныйКаталог, ЦелевойКаталог); //1
Сообщить("Скопировано файлов: " + Сч);
КонецПроцедуры

Как это работает

Выше мы рассмотрели, как может выглядеть «новый» асинхронный код. Теперь настало время разобраться, как это работает.

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

Новое состоит в том, что в операторе Ждать выполнение Асинх процедуры/функции может приостанавливаться и возобновляться. Приостановка означает выход из процедуры/функции с возможностью последующего продолжения. Но элемент стека вызовов, соответствующий приостановленной процедуре/функции не очищается и не удаляется. И при возобновлении выполнение начинается с той же точки, где оно было приостановлено с тем же окружением, включая значения локальных переменных, что было до приостановки.

Таким образом, выполнение оператора Ждать выглядит следующим образом:

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

Можно попробовать провести параллель между «новой» и «старой» асинхронностью. Рассмотрим небольшой фрагмент, выполняющий копирования файла с применением старой техники работы с асинхронностью.

&НаКлиенте
Процедура СкопироватьФайл(ИсхФайл, ЦелФайл)
Описание = Новый ОписаниеОповещения("ПослеКопирования", ЭтотОбъект);
НачатьКопированиеФайла(Описание, ИсхФайл, ЦелФайл);
КонецПроцедуры

Процедура ПослеКопирования(Файл, ДопПарам) Экспорт
Сообщить("Скопирован файл: " + Файл);
КонецПроцедуры

Глядя на этот пример, можно сказать, что приостановка выполнения происходит на время выполнения «старой» асинхронной процедуры НачатьКопированиеФайла(), а возобновление выполнения происходит при завершении ее выполнения и заключается в вызове процедуры ПослеКопирования().

Теперь тот же фрагмент, написанный по-новому.

&НаКлиенте
Асинх Функция СкопироватьФайл(ИсхФайл, ЦелФайл)
Об = КопироватьФайлАсинх(ИсхФайл, ЦелФайл);
Ждать Об;
Сообщить("Скопирован файл: " + ЦелФайл);
КонецФункции

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

Покажем на примере, что происходит при выполнении «нового» асинхронного кода. В качестве примера возьмем уже известный модуль формы, копирующий файлы из одного каталога в другой. Но для большей наглядности совсем чуть-чуть перепишем его.

&НаКлиенте
Асинх Процедура КопироватьФайлы(Команда)
Об = КопироватьФайлыАсинх(ИсходныйКаталог, ЦелевойКаталог); //(1)
Сч = Ждать Об; //(4) (10)
Сообщить("Скопировано файлов: " + Сч);
Возврат; //(11)
КонецПроцедуры

&НаКлиенте
Асинх Функция КопироватьФайлыАсинх(ИсхКаталог, ЦелКаталог)
Об1 = НайтиФайлыАсинх(ИсхКаталог, "*", Ложь); //(2)
Файлы = Ждать Об1; //(3) (5)
Счетчик = 0;
Для Каждого Файл Из Файлы Цикл
ИсхФайл = ИсхКаталог + "/" + Файл.Имя;
ЦелФайл = ЦелКаталог + "/" + Файл.Имя;
Об2 = КопироватьФайлАсинх(ИсхФайл, ЦелФайл); //(6)
Ждать Об2; //(7) (8)
Счетчик = Счетчик + 1;
КонецЦикла;
Возврат Счетчик; //(9)
КонецФункции

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

  • Начало выполнения процедуры КопироватьФайлы(). Вызов функции КопироватьФайлыАсинх().

  • Начало выполнения функции КопироватьФайлыАсинх(). Вызов асинхронной функции платформы НайтиФайлыАсинх().

  • Приостановка в операторе Ждать до завершения Об1. Возврат в процедуру КопироватьФайлы().

  • Приостановка в операторе Ждать до завершения Об (КопироватьФайлыАсинх()).

  • Возобновление выполнения КопироватьФайлыАсинх() в свзязи с завершением Об1 (НайтиФайлыАсинх()). Переменной Файлы присваивается результат поиска. Или, если при выполнении НайтиФайлыАсинх() произошла ошибка, выбрасывается исключение.

  • Вызов асинхронной функции платформы КопироватьФайлАсинх().

  • Приостановка функции КопироватьФайлыАсинх() до завершения Об2 (КопироватьФайлАсинх()).

  • Возобновление выполнения КопироватьФайлыАсинх() в взязи с завершением Об2 (КопироватьФайлАсинх()). Если при выполнении КопироватьФайлАсинх() произошла ошибка, выбрасывается исключение.

  • Окончательный выход из КопироватьФайлыАсинх(). Обещание, возвращенное функцией КопироватьФайлыАсинх() на шаге (3) переходит в состояние Success и становится контейнером для значения, содержащегося в переменной Счетчик.

  • Возобновление выполнения процедуры КопироватьФайлы() в связи  с завершением Об (КопироватьФайлыАсинх()). Переменной Сч присваивается число скопированных файлов. Или, если при выполнении КопироватьФайлыАсинх() было выброшено не перехваченное исключение, выбрасывается это же самое исключение.

  • Окончательный выход из процедуры КопироватьФайлы().

Понятно, что шаги (6), (7) и (8) могут быть выполнены несколько раз, в зависимости от числа копируемых файлов.

Заключение

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

Рассказать друзьям: