Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

At the end of an async method, should I return or await?

Tags:

c#

async-await

At the end of a Task-returning async method, if I call another async method, I could either await it or return its task. Which are the consequences of each?

    Task FooAsync()     {         return BazAsync();  // Option A     }      async Task BarAsync()     {         await BazAsync(); // Option B     } 
like image 987
Jay Bazuzi Avatar asked Jul 26 '13 16:07

Jay Bazuzi


People also ask

Do I have to return from async function?

Async functions always return a promise. If the return value of an async function is not explicitly a promise, it will be implicitly wrapped in a promise. Note: Even though the return value of an async function behaves as if it's wrapped in a Promise.resolve , they are not equivalent.

Should you always await async methods?

If a method is declared async, make sure there is an await! If your code does not have an await in its body, the compiler will generate a warning but the state machine will be created nevertheless, adding unnecessary overhead for an operation that will actually never yield.

Why async should not return void?

Async void methods can wreak havoc if the caller isn't expecting them to be async. When the return type is Task, the caller knows it's dealing with a future operation; when the return type is void, the caller might assume the method is complete by the time it returns.

Does return need await?

Most of the time, there is no observable difference between return and return await . Both versions of delay1Second have the exact same observable behavior (but depending on the implementation, the return await version might use slightly more memory because an intermediate Promise object might be created).


1 Answers

You can't return the task if the method itself is declared to be async - so this won't work, for example:

async Task BarAsync() {     return BazAsync(); // Invalid! } 

That would require a return type of Task<Task>.

If your method is just doing a small amount of work and then calling just one async method, then your first option is fine, and means there's one fewer task involved. You should be aware that any exceptions thrown within your synchronous method will be delivered synchronously though - indeed, this is how I prefer to handle argument validation.

It's also a common pattern for implementing overloading e.g. by cancellation token.

Just be aware that if you need to change to await something else, you'll need to make it an async method instead. For example:

// Version 1: Task BarAsync() {     // No need to gronkle yet...     return BazAsync(); }  // Oops, for version 2 I need to do some more work... async Task BarAsync() {     int gronkle = await GronkleAsync();     // Do something with gronkle      // Now we have to await BazAsync as we're now in an async method     await BazAsync(); } 
like image 157
Jon Skeet Avatar answered Oct 02 '22 15:10

Jon Skeet