Asynchronous Blazor InvokeAsync vs Wait InvokeAsync

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的原因是为了防止到处都需要异步代码。但我会在什么情况下等待呢 等待: 非等待丢弃: 这里有一些我见过的不同用法的例子,如果有人能解释或分享他们之间的一

编辑:为了澄清,这在Blazor服务器应用程序中

我对InvokeAsync的正确用法和更新UI感到困惑。文档有几种用法,但没有真正解释等待或不等待的原因。我也看到了一些相互矛盾的线索,没有太多证据支持他们的推理

让所有方法异步等待InvokeAsync(StateHasChanged)似乎是错误的,我在某个地方读到,引入InvokeAsync的原因是为了防止到处都需要异步代码。但我会在什么情况下等待呢

等待:

非等待丢弃:

这里有一些我见过的不同用法的例子,如果有人能解释或分享他们之间的一些差异的信息链接,那就太好了(谢谢!)

IncrementCounter(ButtonClick处理程序)是一个错误的东西——它总是在SyncContext线程上运行,并且总是可以在不调用的情况下使用纯语句HasChanged()

因此,让我们看一个计时器事件。Threading.Timer类不支持异步处理程序,因此您可以在未指定线程上运行
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); 
}