What's the difference between awaiting async Task
function and calling await
inside a void
function?
The whole world! Everything...and then some. Let's take a step back and start with some of the basics.
You should go "async all the way", i.e.; if you're returning an awaitable (Task
or Task<T>
) these should correctly use the async
and await
keywords.
There are several things that need to be clarified here. You should not have async void
methods, instead you should have async Task
- the exception being event handlers (where the delegates are predefined as non-task returning) and the like. Let's examine and pick apart method one (I'm going to ignore the Main
entry points):
One
private async void Initializer()
{
var store = InitLocalStore();
await InitSyncContext(store); // <-- Here, await call
...
}
// Here returns Task (without having a return inside. No compile errors)
private async Task InitSyncContext(MobileServiceSQLiteStore store)
{
await Client.SyncContext.InitializeAsync(store);
}
You have an Initializer
method that is immediately a code smell as it is async void
. This should be async Task
and it should have the "Async" suffix. Additionally, you have an InitSyncContext
that takes on a store
variable and invokes some client initialization work. The code smell here is that you are using async
and await
. This is not need on simple (single task) workloads like this. Instead you should simply use the return
keyword. Example at the very bottom. Let's look at method two:
Two
private void Initializer()
{
var store = InitLocalStore();
InitSyncContext(store); // <-- Here without await call
...
}
// Here is void but with a async call inside
private async void InitSyncContext(MobileServiceSQLiteStore store)
{
await Client.SyncContext.InitializeAsync(store);
}
Things have officially gone from bad to worse! With the misconceptions of the asynchronous nomenclatures, we have assumed that since one method appeared to work "ok" without taking into account the best practices that another method could follow suit. You made the InitSyncContext
method async void
. The reason methods should not be async void
is that they are fire-and-forget. The internal async state machine doesn't have a Task
to latch onto and therefore the state is lost. When you remove the caller's await
you are saying start this asynchronous operation but you do not care about it's results.
Here is the correct way to implement the desired functionality:
Correct
private async Task InitializerAsync()
{
var store = InitLocalStore();
await InitSyncContextAsync(store);
...
}
// Simply return the task that represents the async operation and let the caller await it
private Task InitSyncContextAsync(MobileServiceSQLiteStore store)
{
return Client.SyncContext.InitializeAsync(store);
}
A note about the Main
method from your snippets, if this is part of a console application - the top-level entry point into your async stack would invoke either .Result
or .Wait()
.
Further reading