Blazor WebAssembly:如何在长时间运行的非异步过程中更新UI [英] Blazor WebAssembly: How to get UI to update during long running, non-async process

查看:584
本文介绍了Blazor WebAssembly:如何在长时间运行的非异步过程中更新UI的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些复杂的计算需要花费一些时间. (是的,我知道,客户端听起来可能不是理想的选择,但是有充分的理由.)我希望页面随着计算的进行而更新结果.我可以使UI在计算过程中重新呈现,但不能正确更新结果.

I have some complex calculations that take a while to do. (Yes, I know, client-side may not sound like the ideal place to do them, but there are good reasons for it.) I would like the page to update with results as the calculations progress. I can get the UI to re-render as the calculations progress, but not update the results correctly.

请注意,计算本质上是 not 异步的,将它们包装在Task.Run中似乎无济于事.这是演示该问题的代码的简化版本:

Note that the calculations are not inherently async and wrapping them in Task.Run does not seem to help. Here is a simplified version of the code that demonstrates the problem:

@page "/AsyncTest"

<button type="button" class="btn btn-primary" @onclick="@(e => RunOnClick(e))">Run</button>
<br />
<div>Percent Complete = @PercentComplete %</div>

@code {
    private int PercentComplete = 0;

    private async Task RunOnClick(MouseEventArgs e) {
        for (PercentComplete = 0; PercentComplete < 100; PercentComplete += 20) {
            System.Console.WriteLine($"LongCalculation: PercentComplete = {PercentComplete}");

            await Task.Run(() => Calculation()); // Does not work.
            //await CalculationAsync();          // This works.

            StateHasChanged();
        }
    }

    private void Calculation() => System.Threading.Thread.Sleep(500);
    private async Task CalculationAsync() => await Task.Delay(500);

    protected override void OnAfterRender(bool firstRender) {
        System.Console.WriteLine($"OnAfterRender: PercentComplete = {PercentComplete}");
    }
}

单击按钮时,直到完成所有处理后,UI上的完成百分比才会更新,即处理从0%变为100%,而中间没有任何步骤.如果我使用异步版本CalculationAsync(),则UI会按预期进行更新.

When the button is clicked, the Percent Complete on the UI does not update until all the processing is done, i.e. it goes from 0% to 100% without any of the steps in between. If I use async version CalculationAsync() the UI updates as I expect.

这是控制台输出:

blazor.webassembly.js:1 WASM: LongCalculation: PercentComplete = 0
blazor.webassembly.js:1 WASM: OnAfterRender: PercentComplete = 0
blazor.webassembly.js:1 WASM: LongCalculation: PercentComplete = 20
blazor.webassembly.js:1 WASM: OnAfterRender: PercentComplete = 20
blazor.webassembly.js:1 WASM: LongCalculation: PercentComplete = 40
blazor.webassembly.js:1 WASM: OnAfterRender: PercentComplete = 40
blazor.webassembly.js:1 WASM: LongCalculation: PercentComplete = 60
blazor.webassembly.js:1 WASM: OnAfterRender: PercentComplete = 60
blazor.webassembly.js:1 WASM: LongCalculation: PercentComplete = 80
blazor.webassembly.js:1 WASM: OnAfterRender: PercentComplete = 80
blazor.webassembly.js:1 WASM: OnAfterRender: PercentComplete = 100

这表明随着计算的进行,UI正在重新呈现,并且PercentComplete属性正在更新.但是由于某种原因,实际上并未更改UI.我不确定Blazor是否以某种方式缓存了PercentComplete的值,或者它没有意识到它已更改并跳过了渲染的那一部分.

This shows that the UI is being re-rendered and the PercentComplete property is being updated as the calculations progress. For some reason, however, the UI isn't actually being changed. I'm not sure if Blazor is somehow caching the value of PercentComplete or if it doesn't realise that it has changed and skips that bit of the rendering.

有什么想法可以使它正常工作吗?

Any idea how I can get this to work?

注意:此问题与不同17069489 .尽管不是很明显,但该问题涉及的是 异步任务.

Note: This question is not the same as 17069489. Although not obvious, that question deals with tasks that are async.

推荐答案

在Task.Run()中包装同步版本将在Blazor/Server中工作,而在Blazor/Wasm中不行. WebAssembly在单个线程上运行,这仍然是Browser/Wasm的限制.

Wrapping the sync version in Task.Run() will work in Blazor/Server but not in Blazor/Wasm. WebAssembly is running on a single thread, that still is a Browser/Wasm limitation.

将来,当Blazor在Wasm 2上运行并获得真正的线程时,可能会解决该问题.我不知道到期日.

This might be resolved in the future when Blazor runs on Wasm 2 and gets real threading. I don't know of a due date for that.

同时,使用额外的Task.Delay()使循环至少有点异步:

In the mean time, make the loop at least a little bit async with an extra Task.Delay() :

for (PercentComplete = 0; PercentComplete < 100; PercentComplete += 20) 
{
  System.Console.WriteLine($"LongCalculation: PercentComplete = {PercentComplete}");

   Calculation(); // Make the steps as small as possible, Task.Run is of no use

   StateHasChanged();    
   await Task.Delay(1);  // give the UI some time to catch up
}

这篇关于Blazor WebAssembly:如何在长时间运行的非异步过程中更新UI的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆