Asynchronous Blazor InvokeAsync vs Wait InvokeAsync
编辑:为了澄清,这在Blazor服务器应用程序中 我对InvokeAsync的正确用法和更新UI感到困惑。文档有几种用法,但没有真正解释等待或不等待的原因。我也看到了一些相互矛盾的线索,没有太多证据支持他们的推理 让所有方法异步等待InvokeAsync(StateHasChanged)似乎是错误的,我在某个地方读到,引入InvokeAsync的原因是为了防止到处都需要异步代码。但我会在什么情况下等待呢 等待: 非等待丢弃: 这里有一些我见过的不同用法的例子,如果有人能解释或分享他们之间的一些差异的信息链接,那就太好了(谢谢!) IncrementCounter(ButtonClick处理程序)是一个错误的东西——它总是在SyncContext线程上运行,并且总是可以在不调用的情况下使用纯语句HasChanged() 因此,让我们看一个计时器事件。Threading.Timer类不支持异步处理程序,因此您可以在未指定线程上运行Asynchronous Blazor InvokeAsync vs Wait InvokeAsync,asynchronous,async-await,blazor,invoke,blazor-server-side,Asynchronous,Async Await,Blazor,Invoke,Blazor Server Side,编辑:为了澄清,这在Blazor服务器应用程序中 我对InvokeAsync的正确用法和更新UI感到困惑。文档有几种用法,但没有真正解释等待或不等待的原因。我也看到了一些相互矛盾的线索,没有太多证据支持他们的推理 让所有方法异步等待InvokeAsync(StateHasChanged)似乎是错误的,我在某个地方读到,引入InvokeAsync的原因是为了防止到处都需要异步代码。但我会在什么情况下等待呢 等待: 非等待丢弃: 这里有一些我见过的不同用法的例子,如果有人能解释或分享他们之间的一
void Tick(){…}
这里确实需要InvokeAsync(StateHasChanged)
。您可以将Tick方法设置为async void
,只是为了等待InvokeAsync,但这会给出错误的信号。不使用await
而使用InvokeAsync是较小的缺点
void Tick() // possibly threaded event handler
{
_counter++;
InvokeAsync(StateHasChanged); // fire-and-forget mode
}
但是,当您使用异步方法并且仍然需要InvokeAsync时,等待它会更整洁,因为您可以
async Task SomeService()
{
_counter++;
await InvokeAsync(StateHasChanged);
}
为什么要使用
InvokeAsync
StateHasChanged
不会修改任何UI,也不会阻塞,它会告诉Blazor某个组件已更改,Blazor应该重新绘制该组件。事实上,甚至可能不需要StateHasChanged
。在Blazor教程中,因为Blazor本身检测到计数器changed@Panagiotis卡那沃斯,对不起,你完全错了。InvokeAsync在Blazor服务器应用程序等多线程环境中是必需的。目前,在WebAssembly Blazor应用程序中不需要它,但建议使用它,因为WebAsembly的未来更改也将变成多线程。是的,这可能是我的一个错误,我忘了提到这是针对Blazor服务器的。需要在主线程(UI线程)上执行InvokeAsync。如果尝试在另一个线程上调用StateHasChanged,它将抛出InvalidOperationException。Blazor WebAssembly在编写本文时是单线程的,因此您可以不使用它,但将来它可能会中断。@StephenCleary-Blazor有自己的InvokeAsync(),特别是用于此目的。它也有自己的SynchronizationContext,但没有很好的文档记录。
public async Task IncrementCounter()
{
_counter++;
await InvokeAsync(StateHasChanged);
}
public async Task IncrementCounter()
{
await InvokeAsync(() =>
{
_counter++;
StateHasChanged();
});
}
void Tick() // possibly threaded event handler
{
_counter++;
InvokeAsync(StateHasChanged); // fire-and-forget mode
}
async Task SomeService()
{
_counter++;
await InvokeAsync(StateHasChanged);
}