Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Callback with async and await

I have questions regarding the execution order of async jobs.

I will ask my question with example because it is easier to be understandable.

It is an official example from https://msdn.microsoft.com/en-us/library/mt674882.aspx with some twist.

async Task<int> AccessTheWebAsync()
{ 
    HttpClient client = new HttpClient();

    //async operation:
    Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");

    // You can do work here that doesn't rely on the string from GetStringAsync.
    DoWork1();

    // The await operator suspends AccessTheWebAsync.
    string urlContents = await getStringTask;

    DoWork2();

    return urlContents.Length;
}

Can I say DoWork2 is a callback of client.GetStringAsync?

If so, DoWork2 is not immediately executed following the completion of client.GetStringAsync IF DoWork1 runs longer time than client.GetStringAsync.

Am I right here?

like image 964
derek Avatar asked Sep 02 '16 06:09

derek


People also ask

Can we use async await with callback?

The await keyword is used in an async function to ensure that all promises returned in the async function are synchronized, ie. they wait for each other. Await eliminates the use of callbacks in . then() and .

How do you do asynchronous callback?

Callbacks. An event handler is a particular type of callback. A callback is just a function that's passed into another function, with the expectation that the callback will be called at the appropriate time. As we just saw, callbacks used to be the main way asynchronous functions were implemented in JavaScript.

What are callbacks promises and async await?

Callback, Promises, and Async-await are a way to deal with asynchronous data. Asynchronous programming in JavaScript is a way in which the program doesn't wait until the execution of something is going on. This comes in handy when we do an API call to fetch some data, which takes some time (maybe 2–3 sec).

Why is async await better than callbacks?

Async functions not only allow the programmer to escape from callback hell and promise chaining in asynchronous code, but they also make the code seemingly synchronous.


2 Answers

DoWork2 is not immediately executed following the completion of client.GetStringAsync if DoWork1 runs longer time than client.GetStringAsync

Once you hit that point await client.GetStrinkAsync, DoWork1() has already completed, as from your example it looks as it's execution is synchronous. Once client.GetStringAsync completes, then DoWork2 is set to execute.

The execution flow will be:

  1. GetStringAsync asynchronously starts. It is executed until it hits it's first internal await, and then yields control back to AccessTheWebAsync.
  2. DoWork1() kicks off. As it's synchronous, everyone waits for it's completion
  3. client.GetStringAsync is asynchronously waited for completion. await will naturally yield the control of execution to it's caller.
  4. Once client.GetStringAsync completes, execution will return to AccessTheWebAsync and DoWork2() will execute synchronously.
  5. urlContents.length will be returned.

Generally, everything after the first await keyword is set to be the continuation for the rest of the method.

like image 126
Yuval Itzchakov Avatar answered Sep 30 '22 16:09

Yuval Itzchakov


Yuval's answer is correct.

To answer your followup question:

Is there a way to make the DoWork2 immediately executed once client.GetStringAsync is finished?

Possibly. It depends on the context of this code. It's not possible to have DoWork1 and DoWork2 both running on the UI thread at the same time (obviously, a single thread can only do one thing at a time). But if this is called from a thread pool context, then sure, it's possible to run them both simultaneously.

However, you should shift your thinking from "callback" to "operation". That is, don't think of it as DoWork2 being a "callback" of GetStringAsync. Instead, think of it like this: I have an operation GetStringAsync, and I have an operation DoWork2; I need a new operation that does one and then the other.

Once you shift your thinking this way, the solution is to write a method for the new operation:

async Task<string> GetStringAndDoWork2Async()
{
  HttpClient client = new HttpClient();
  var result = await client.GetStringAsync("http://msdn.microsoft.com");
  DoWork2();
  return result;
}

Now you can use that new operation in your higher-level method:

async Task<int> AccessTheWebAsync()
{
  var task = GetStringAndDoWork2Async();

  DoWork1();

  string urlContents = await task;

  return urlContents.Length;
}
like image 23
Stephen Cleary Avatar answered Sep 30 '22 17:09

Stephen Cleary