await expression can be used to write asynchronous code in a linear fashion. It can be applied to methods that return a
Task or Future, as well as to methods that expect a callback closure as final parameter.
Code can be written as if the methods in question return a value right away, and the compiler will handle the task of unwrapping the provided code and handle the callbacks properly. Under the hood,
await will break the method into different parts, scheduling them to be executed asynchronously once the awaited actions have been completed.
Await with Tasks
Task type either explicitly, or using language sugar such as the C#
async keyword. The returned
Task instance can be used to keep track of the status, and be notified when the result is available – which the
await keyword abstracts:
method Test: Task<String>; begin var task := new Task<String>(-> begin Thread.Sleep(10000); exit 'Result!' end); task.Start(); exit task; end; ... method OtherMethod(); begin var lMessage := await Test(); writeLn(lMessage); end;
At the point of the
await in OtherMethod, the actual method containing the await call will finish. All subsequent code (such as the call to
writeLn in the example above) will be wrapped in a helper type, and execute once the task as completed.
Await with Closures
Await can also be used with methods that take a "callback" closure as last parameter. The parameters of the closure will turn into return values of the call. For example consider the following call using Elements RTL's
method DownloadData; begin Http.ExecuteRequestAsJson(new HttpRequest(URL), (aResponse) -> begin if assigned(aResponse.Content) then begin dispatch_async(dispatch_get_main_queue(), () -> begimn // show data end); end; end); end;
This code uses two nested closures, first to wait for the response of tne network request, and then to process its results on the main UI thread. With
await this can be unwrapped nicely:
method DownloadData; begin var lResponse := await Http.ExecuteRequestAsJson(new HttpRequest(URL)); if assigned(lResponse.Content) then begin await dispatch_async(dispatch_get_main_queue()); // show data end; end;
Note how the parameter of the first closure,
aResponse becomes a local variable,
lResponse, and how
await is used without return value on the
For callbacks that return more than one parameter,
await will return a Tuple, e.g.:
var (aValue, aError) := await TryToGetValueOrReturnError(); ...
Await with Asynchronous Sequences
On the .NET platform,
await can also be used to loop an Asynchronous Sequence. Here the
await keyword is followed by the
for each keywords defining a regular
for Loop. Each individual entry in the sequence will be await'ed and the loop will be run for it. Execution after the loop will continue after all items have been processed and the end of the asynchronous sequence has been reached.
var lItems: async sequence of String := ...; await for each i in lItems do writeLn(el); writeLn("Done");
awaitkeyword in C#
__awaitkeyword in Swift
- Asynchronous Sequences
Await for Closure Callbacks is unique to Elements, and is available in RemObjects C# and Swift, as well.