简体   繁体   中英

async Task with HttpClient

public async Task<IReadOnlyCollection<OrderItem>> GetOrderItemsAsync()
{
    var items = await httpClient.GetFromJsonAsync<IReadOnlyCollection<CatalogItemDto>>("items");
    return items;
}

I have an asynchronous Task method that has an asynchronous HttpClient . How do HttpClient and async Task work together?

I do know what asynchronous task is, but combining both for the above example, I wanted to know how it works behind the scene.

Please help me understand the nitty gritty behind the scene. Currently whenever I see async Task I just put await without knowing internally how the compiler performs.

A correct, but also a bit useless, answer is: async/await creates a state machine in the background.

But we can do better. Lets start with what a Task is. This is an object that holds some function inside that is supposed to be called at some point in the future (as a reaction to some event). If that function returns something (or throws an exception) the result will be stored on the Task to be used later.

In order to execute those Tasks you need a TaskScheduler. This is some object that decides when, how and what Tasks are executed, on what threads, reacting to what events, etc. So for example if we have a method that reads from a disk and returns Task, then it starts reading from the disk, it immediatly returns a Task, and tells the TaskScheduler "hey, once I finish reading from the disk, execute this Task for me, ok?". Thus the operation of reading from the disk happens in the background (it is i/o after all) and the CPU is free to do other things in the meantime.

And another feature of Tasks is that they can be chained. Meaning, we can attach a new Task to old Task, which will be executed after the old Task is done. In the old days we would do something like this:

// Say these two are given.
Task<User> GetUserByEmail(string email);
Task<List<Order>> GetOrdersForUser(int userId);

Task<List<Order>> GetOrdersByEmail(string email)
{
    var tcs = new TaskCompletionSource<List<Order>>();

    GetUserByEmail(email)  // T1
        .ContinueWith((prevTask) =>
        {
            // This will be executed only when T1 is done.
            GetOrdersForUser(prevTask.Result.Id)  // T2
                .ContinueWith((prevTask) =>
                {
                    // This will be executed when T2 is done.
                    tcs.TrySetResult(prevTask.Result);
                });
        });

    return tcs.Task;
}

But people realized that this kind of coding can quickly become unreadable when lots of async calls happens. This is also known as "callback hell" (the term taken from JavaScript).

What async/await does is simply it solves this readability issue. Indeed, by applying it, the code above can be rewritten as:

async Task<List<Order>> GetOrdersByEmail(string email)
{
    var user = await GetUserByEmail(email);
    return await GetOrdersForUser(user.Id);
}

Much better, don't you think? Technically these are not the same (I didn't do any error handling in "callback hell" version, which would make it even worse). The compiler actually produces a different code for async/await (so called async state machine, you can see how it works by looking at https://sharplab.io/ for example), but functionally these are quite close.

The whole point of async/await is simply to make the code cleaner. It is a syntactic feature.

I have an asynchronous Task method that has a synchronous HttpClient .

HttpClient is neither synchronous or asynchronous. Only methods can be synchronous or asynchronous. And the concrete method you use GetFromJsonAsync is asynchronous, it even has Async in the name. :) Well, it is not necessarily asynchronous (this actually depends on the implementation, in fact you could write a synchronous code that returns a completed task), but it does return a Task that we can await.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM