在 blazor 服务器应用程序中,是否可以非常频繁地发送事件和调用 StateHasChanged
,例如每秒 500 次?
我的一个页面需要对外部事件做出反应,然后相应地更新其状态。我找到了以下解决方案:
InvokeAsync(() => StateHasChanged())
。这已经可以正常工作了。但是,该事件可能会经常发生,例如每秒500次,我担心客户端和服务器的性能。不幸的是,我不明白哪一部分发生在服务器上,哪一部分发生在客户端上,以及它们之间发送了哪些数据。
StateHasChanged
后实际呈现页面?我认为这会给客户端带来很高的 CPU 负载。答案 0 :(得分:3)
为了回答您的一些问题,当您在服务器模式下运行时,所有实际工作都在 Blazor Hub 会话中进行。
调用 StateHasChanged
的真正作用是将 RenderFragment
排入 Hub 会话中的渲染器队列。这是来自 ComponentBase
的代码。
_renderFragment = builder =>
{
_hasPendingQueuedRender = false;
_hasNeverRendered = false;
BuildRenderTree(builder);
};
StateHasChanged
看起来像这样:
protected void StateHasChanged()
{
if (_hasPendingQueuedRender) return;
if (_hasNeverRendered || ShouldRender())
{
_hasPendingQueuedRender = true;
try
{
_renderHandle.Render(_renderFragment);
}
catch
{
_hasPendingQueuedRender = false;
throw;
}
}
}
StateHasChanged
仅在新渲染事件尚未排队时才将其排队。渲染后,渲染器差异引擎会检测任何更改,并通过 SignalR 将这些更改发送到客户端浏览器会话。
所以没有变化,没有客户端活动,只有大量的服务器绑定活动处理事件并计算出任何变化。对服务器的影响将取决于您有多少可用的服务器功率。
答案 1 :(得分:1)
看起来 Blazor 服务器每秒可以发送数百个更改:
@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++;
}