pschill
pschill

Reputation: 5569

Frequent page updates in blazor server application

In a blazor server application, is it okay to send events and call StateHasChanged very often, e.g., 500 times per second?

One of my pages needs to react to an external event and then update its state accordingly. I found the following solution:

This already works correctly. However, the event may occur very often, e.g., 500 times per second, and I worry about the performance of client and server. Unfortunately, I dont understand which part happens on the server, which part happens on the client, and which data is sent between them.

Upvotes: 1

Views: 953

Answers (2)

dani herrera
dani herrera

Reputation: 51645

It looks that Blazor server can send hundreds of changes by second:

enter image description here

@page "/"
Tics per second: <input type="range" min="1" max="2000" @bind="@CurrentValue" class="slider" id="myRange"> @CurrentValue
<div style="width:500px; height:10px; background-color: blue; position: relative;">
    <div class="ball" style="@position_txt"></div>
</div> <br/><br/>
<span>@DateTime.Now.ToString("HH:mm:ss")</span>
<span>Number of renders: @nRenders.ToString("N0")</span>
<button type="button" @onclick="start">start</button>
<style>
 .ball {width: 30px; height: 30px; top: -10px;
        position: absolute; background-color: blue;}
</style>
@code
{
    Int64 nRenders = 0, v = 1, position = 10, CurrentValue = 10;
    string position_txt => $"left: {position}px;";
    private static System.Timers.Timer aTimer = new System.Timers.Timer();
    protected void start()
    {
        move();
        aTimer.Elapsed += (source, e) => move();
        aTimer.AutoReset = true;
        aTimer.Enabled = !aTimer.Enabled;
    }
    protected void move()
    {
        aTimer.Interval = 1000.0/CurrentValue;
        position = (position+v);
        if (position>500 || position<0) v *= -1;
        InvokeAsync(StateHasChanged);
    }
    protected override void OnAfterRender(bool firstRender) => nRenders++;
}

Upvotes: 3

MrC aka Shaun Curtis
MrC aka Shaun Curtis

Reputation: 30001

To answer some of your questions, as your running in Server mode all the real work takes place in the Blazor Hub session.

What a call to StateHasChanged really does is queue a RenderFragment onto the Renderer Queue in the Hub Session. Here's the bit of code from ComponentBase.

           _renderFragment = builder =>
            {
                _hasPendingQueuedRender = false;
                _hasNeverRendered = false;
                BuildRenderTree(builder);
            };

StateHasChanged looks like this:

       protected void StateHasChanged()
        {
            if (_hasPendingQueuedRender) return;
            if (_hasNeverRendered || ShouldRender())
            {
                _hasPendingQueuedRender = true;
                try
                {
                    _renderHandle.Render(_renderFragment);
                }
                catch
                {
                    _hasPendingQueuedRender = false;
                    throw;
                }
            }
        }

StateHasChanged only queues a new render event if one isn't already queued. Once rendered, the Renderer diffing engine detects any changes and sends just those changes to the Client Browser Session over SignalR.

So no changes, no client activity, just lots of server bound activity dealing with the events and working out any changes. The impact on the server will depend upon how much server power you have available.

Upvotes: 3

Related Questions