C# Async/Await - The death of callback hell.
What is async/await?
Simply put, async
and await
are syntactic sugar for the handling callbacks. The basic idea is that when you call a method with await
, it tells the compiler to wrap that bad boy in a Task
and to pass it to the Task Scheduler. The Task Scheduler then executes the Task
, and then the code following the await
that is dependant on the Task
is run. The two following examples are functionally equivalent, but the Async/Await way is more readable.
Callback flow
class Program
{
public static void Main(string[] args)
{
Console.WriteLine("Run Callack");
GetPosts( results => Console.WriteLine($"GET /Posts (Callback):{results}") );
}
static void GetPosts( Action<string> callback )
{
using (var client = new WebClient())
{
client.DownloadStringCompleted += (sender, e) =>
{
Console.WriteLine( "Runing WebClient Callback");
string pageSourceCode = e.Result;
callback(pageSourceCode);
};
client.DownloadStringAsync(new Uri("https://jsonplaceholder.typicode.com/posts/"));
}
}
}
Async/Await flow
class Program
{
public static async Task Main(string[] args)
{
Console.WriteLine("Run Async");
Console.WriteLine($"GET /Posts (async): {await GetPostsAsync()}");
}
static Task<string> GetPostsAsync()
{
using (var client = new HttpClient())
{
return new HttpClient().GetStringAsync("https://jsonplaceholder.typicode.com/posts/");
}
}
}
*See The Awesomeness that is async Main()
WTF are Tasks
Task
are basically what they sound like they are, little bits of work, that can be done asynchronously. They generally come in two varity: Task
and Task<T>
where T is the “return” value of the Task
. In case it isn’t obvious, you would use the generic Task<T>
when you need to retrieve a value, otherwise just return the plain ol Task
.
Got’yas
There are a couple things you need to keep in mind when working with async/await:
Task
s are not threads.Task
s that areawait
ed run in a sequential queue unless told to do otherwise, ieParalell.ForEach()
. Think nested callbacks for eachawait
(not exactly but close enought for this article).Task
s may be run on a different thread then called, but the results are then marshalled to the calling thread.Task
s are cheap but not free. Every time you wrap/unwrap aTask
withawait
you are paying a cost.
Da Rulze
- If you don’t need the
await
ed value in a method, don’t use theasync
keyword and just return the unadulteratedTask
. - Methods should return either
Task
orTask<T>
except for when called by an event delegate, ie.Button.clicked
then they may returnvoid1
. - Method names should end with the word ‘Async’.
- “Async all the way”, Don’t be switching between synchronous and asynchronous. Pick one, and be confident with your decision.
Until next time, keep Hackin’.