本文介绍了Blazor中的StateHasChanged()与InvokeAsync(StateHasChanged)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道调用 StateHasChanged()方法会通知组件状态已更改并且应该重新呈现.中调用 StateHasChanged()-而不是 InvokeAsync(StateHasChanged)-code>事件,它可以按预期运行,没有任何问题.我应该改为调用 await InvokeAsync(StateHasChanged)吗?如果是的话,为什么到底是什么?我觉得这里可能有一些我不知道的重要细微差别.

I have tried calling StateHasChanged() - instead of InvokeAsync(StateHasChanged) - in a Timer's Elapsed event, and it works as expected, without any issues. Should I be calling await InvokeAsync(StateHasChanged) instead?! And if so, why exactly? I feel like there's probably some important nuance here that I'm unaware of.

我也见过像 InvokeAsync(()=> InvokeAsync(Something))这样的调用,为什么呢?

I've also seen calls like InvokeAsync(() => InvokeAsync(Something)), again, why?

另外,我有时还会看到在没有 await 的情况下调用 InvokeAsync()的方法,该怎么办?!

Plus, I also sometimes see InvokeAsync() called without await, what the deal with that?!

推荐答案

那一定是在WebAssembly上.当您在Blazor Serverside上尝试该操作时,我会期望出现异常.StateHasChanged()检查它是否在正确的线程上运行.

That must have been on WebAssembly. When you try that on Blazor Serverside I would expect an exception. StateHasChanged() checks if it runs on the right thread.

核心问题是渲染和​​调用StateHasChanged都必须在主(UI)线程上进行.DOM的卷影副本不是线程安全的.

The core issue is that the rendering and calling StateHasChanged both have to happen on the main (UI) thread. The shadow copy of the DOM is not thread-safe.

主要的Blazor生命周期事件(OnInit,AfterRender,ButtonClick)都在该特殊线程上执行,因此在极少数情况下,您需要StateHasChanged()即可在没有InvokeAsync()的情况下调用它.

The main Blazor life-cycle events (OnInit, AfterRender, ButtonClick) are all executed on that special thread so in the rare case that you need StateHasChanged() there it can be called without InvokeAsync().

计时器是不同的,它是外部事件".因此您无法确定它会在正确的线程上执行.InvokeAsync()将工作委托给Blazor的SynchronizationContext,以确保它确实在主线程上运行.

A Timer is different, it is an "external event" so you can't be sure it will execute on the correct thread. InvokeAsync() delegates the work to Blazor's SynchronizationContext that will ensure it does run on the main thread.

但是Blazor WebAssembly只有1个线程,因此暂时外部事件也总是在主线程上运行.这意味着当您错误地执行此Invoke模式时,您将不会注意到任何东西.直到一天,当Blazor Wasm最终获得真实线程时,您的代码才会失败.您的计时器也会进行实验.

But Blazor WebAssembly only has 1 thread so for the time being external events always run on the main thread too. That means that when you do this Invoke pattern wrong you won't notice anything. Until one day, when Blazor Wasm finally gets real threads, your code will fail. As will your Timer experiment.

在.net中,同步上下文确定等待之后(之后)发生的情况.不同的平台具有不同的设置,Blazor synccontext非常类似于WinForms和WPF.主要是默认值是 .ConfigureAwait(true):在同一线程上恢复.

In .net a sync context determines what happens with (after) await. Different platforms have different settings, the Blazor synccontext is a lot like that of WinForms and WPF. Mainly, the default is .ConfigureAwait(true): resume on the same thread.

有时我会在顶级Blazor Wasm代码中看到 .ConfigureAwait(false).当我们在那里找到真正的线程时,也将崩溃.可以在blazor调用的服务中使用它.

I sometimes see .ConfigureAwait(false) in toplevel Blazor Wasm code. That too will blow up when we get real threads there. It is fine to use in services called from blazor.

最后, await InvokeAsync(StateHasChanged) await InvokeAsync(()=> StateHasChanged()与C#中的lambda无关,与Blazor无关.第一种简写形式效率更高.

And finally, await InvokeAsync(StateHasChanged) or await InvokeAsync(() => StateHasChanged() is just about lambda's in C#, nothing to do with Blazor. The first short form is a little more efficient.

尽管通常会起作用,但这从来不是一个好主意.比将调用方法(如Timer的OnTick)设置为 async void 更好,因此请在同步代码中使用它.

That is never a good idea, although it will usually work. It is better than making the calling method (like the Timer's OnTick) an async void, so use this in synchronous code.

这篇关于Blazor中的StateHasChanged()与InvokeAsync(StateHasChanged)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

06-30 01:44