从 Blazor 客户端的长 运行 后台任务中释放 UI 的推荐方法是什么
What is the recommended way to release the UI from a long running background task in Blazor client-side
我们的 Blazor(客户端)应用程序由许多同时存在于 UI 上的组件组成。其中之一必须对 Azure SQL 进行大量大数据调用。该组件执行这些调用,无论它是否具有 UI 焦点。这些调用中的每一个最多可能需要 3 秒才能 return 其结果,在此期间它会呈现 UI 无响应。我们如何在不使用 Blazor 服务器端的情况下在这些调用期间保持 UI 响应。使用 Task.Run 等在单线程架构中没有帮助。使用加载微调器也不是一种选择,因为这仍然会使 UI 无响应并且可能对用户不可见。在当前的 Blazor 0.9.0 中有什么方法可以实现这个目标吗?
运行 最新的 Blazor 预览版 (0.9.0-preview3-19154-02)
如果异步调用没有帮助,那么您可以使用浏览器工作者,只需要实现一些 js 互操作。
你可以使用Invoke
,我修改了counter
示例页面来说明它,你需要一种单例DI对象来避免运行两次过程。
记住Blazor
是一个实验项目。另外,这个答案也是一种实验方法。
@page "/counter"
<h1>Counter</h1>
<p>Current count: @currentCount</p>
<button class="btn btn-primary" onclick="@IncrementCount">Click me</button>
@functions {
int currentCount = 0;
void IncrementCount()
{
currentCount++;
}
protected override void OnInit()
{
Invoke(
//here your task.
async () =>
{
for(var i =0; i< 50; i++)
{
await Task.Delay(1000);
currentCount++;
StateHasChanged();
System.Console.WriteLine("Still running ...");
}
});
}
}
我已经成功使用 Task().Start()
像这样将您的工作放在异步任务中:
async Task MyWork()
{
//sleep 10000
}
现在从任何你不希望这项工作阻止呼叫的地方:
new Task( () => MyWork()).Start() );
我只在 Blazor 服务器上使用过它,所以没有在客户端 Blazor 上测试过它,我听说它可能有不同的结果,因为它在单个线程上 运行。
建议的答案无效,对我来说,我最终使用了:
protected override void OnInitialized()
{
InvokeAsync(async () =>
{
myvar = await YourCodeHere();
StateHasChanged();
});
base.OnInitialized();
}
public async Task<MyVarType> YourCodeHere()
{
...
}
说明:我有一个名为 MyVarType 的 class,我用它来在 Razor 组件上显示值。我有一个用 class 实例化的 myVar 变量,最初它是空的。该组件将立即呈现其默认值。初始化后,变量也会从 OnInitialized 方法异步分配。 YourCodeHere 函数可能需要几秒钟。 Razor 组件在调用 StateHasChanged() 时重新呈现,因此它显示加载的值。
我们的 Blazor(客户端)应用程序由许多同时存在于 UI 上的组件组成。其中之一必须对 Azure SQL 进行大量大数据调用。该组件执行这些调用,无论它是否具有 UI 焦点。这些调用中的每一个最多可能需要 3 秒才能 return 其结果,在此期间它会呈现 UI 无响应。我们如何在不使用 Blazor 服务器端的情况下在这些调用期间保持 UI 响应。使用 Task.Run 等在单线程架构中没有帮助。使用加载微调器也不是一种选择,因为这仍然会使 UI 无响应并且可能对用户不可见。在当前的 Blazor 0.9.0 中有什么方法可以实现这个目标吗?
运行 最新的 Blazor 预览版 (0.9.0-preview3-19154-02)
如果异步调用没有帮助,那么您可以使用浏览器工作者,只需要实现一些 js 互操作。
你可以使用Invoke
,我修改了counter
示例页面来说明它,你需要一种单例DI对象来避免运行两次过程。
记住Blazor
是一个实验项目。另外,这个答案也是一种实验方法。
@page "/counter"
<h1>Counter</h1>
<p>Current count: @currentCount</p>
<button class="btn btn-primary" onclick="@IncrementCount">Click me</button>
@functions {
int currentCount = 0;
void IncrementCount()
{
currentCount++;
}
protected override void OnInit()
{
Invoke(
//here your task.
async () =>
{
for(var i =0; i< 50; i++)
{
await Task.Delay(1000);
currentCount++;
StateHasChanged();
System.Console.WriteLine("Still running ...");
}
});
}
}
我已经成功使用 Task().Start()
像这样将您的工作放在异步任务中:
async Task MyWork()
{
//sleep 10000
}
现在从任何你不希望这项工作阻止呼叫的地方:
new Task( () => MyWork()).Start() );
我只在 Blazor 服务器上使用过它,所以没有在客户端 Blazor 上测试过它,我听说它可能有不同的结果,因为它在单个线程上 运行。
建议的答案无效,对我来说,我最终使用了:
protected override void OnInitialized()
{
InvokeAsync(async () =>
{
myvar = await YourCodeHere();
StateHasChanged();
});
base.OnInitialized();
}
public async Task<MyVarType> YourCodeHere()
{
...
}
说明:我有一个名为 MyVarType 的 class,我用它来在 Razor 组件上显示值。我有一个用 class 实例化的 myVar 变量,最初它是空的。该组件将立即呈现其默认值。初始化后,变量也会从 OnInitialized 方法异步分配。 YourCodeHere 函数可能需要几秒钟。 Razor 组件在调用 StateHasChanged() 时重新呈现,因此它显示加载的值。