Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Blazor UI freeze even when Task is used

Consider the Blazor WebAssembly App (ASP. NET Core hosted) "empty" project. I adjusted the Counter page as follows:

<button class="btn btn-primary" @onclick="IncrementCountAsync">Click me</button>

and its Counter.razor.cs file:

public partial class Counter
{
    private static int currentCount = 0;

    private async Task IncrementCountAsync()
    {
        Console.WriteLine("Increment called");

        _ = HeavyComputeAsync();

        currentCount++;

        Console.WriteLine($"Counter = {currentCount}");
    }

    private static Task<int> HeavyComputeAsync()
    {
        return Task.Run(() =>
        {
            Console.WriteLine("Task start");

            for (long ndx = 0; ndx < 1000000; ++ndx)
                ndx.ToString();

            Console.WriteLine("Task end");
            return 0;
        });
    }
}

I'm calling the HeavyComputeAsync method as _ = ... which should not wait until the IncrementCountAsync method finishes, but immediately update the currentCount.

When I run the application I can see in the console the expected behavior:

Increment called
Counter = 1
Task start
Task end (after a while)

However the UI freezes, it does not update the counter. To be exact sometimes it immediately updates :-O, however most of the time the counter is updated after the task is finished only.

I expected the Task runs in parallel (in another thread) and should not block the UI.

I know the IncrementCountAsync runs synchronously in this case since I'm calling _ = HeavyComputeAsync. I tried to call it with await = ... but even in such case the UI is frozen, I can't click other pages.

How can I achieve the UI immediate update?

Thanks, Csaba :-)

like image 893
Csaba Avatar asked May 18 '20 07:05

Csaba


People also ask

Is Blazor slower?

Performance. Blazor projects are slow on the client-side because you have to download the entire dot net runtime along with the necessary DLL libraries on your browser.

Should I use Blazor Wasm or server?

Versus Blazor Server: The Blazor Server hosting model offers several benefits: Download size is significantly smaller than a Blazor WebAssembly app, and the app loads much faster. -The app takes full advantage of server capabilities, including the use of .

Is Blazor worth using?

The framework enables developers to build interactive and reusable web UI in existing web technologies like C# or HTML. When it comes to grammar and syntax, the framework allows developers to use the ones of Razor and C#. Even though Blazor has accumulated only 9k+ starts on GitHub, it's still worth considering.


2 Answers

In Blazor WebAssembly you only have 1 thread. That is (currently) a Browser / JavaScript limitation that also holds for all Wasm applications.

So Task.Run() does not work as it would on the Server. The code will have to execute on the main thread.

Any 'heavy operation' will block the UI, that is the expected behaviour.

The only thing you can do here is to break it into a number of smaller steps and run those with or without Task.Run(), the UI can be made to update in the gaps between them.

I have posted a related answer with sample code here

like image 152
Henk Holterman Avatar answered Sep 29 '22 08:09

Henk Holterman


Your class should be like the one below. Realize that Blazor WebAssembly runs under the same thread JavaScript runs; that is, a single UI thread. So using Task.Run here does not work. Use Task.Delay as I do here, and verify if the async feature of Blazor works. Yes, it does. You should also realize in this context that asynchronous is not parallelism programming, when two or more threads run in parallel.

public partial class Counter
{
    private static int currentCount = 0;

    private async Task IncrementCountAsync()
    {
        Console.WriteLine("Increment called");

        currentCount++;



        await Task.Delay(5000);

        Console.WriteLine($"Counter = {currentCount}");


    }

}

The code here is for demo purposes only, but if you want to perform a long running operation you may use this sample code

like image 27
enet Avatar answered Sep 29 '22 06:09

enet