[英]Why a simple await Task.Delay(1) enables parallel execution?
[英]Why use await Task.Delay(1) in Blazor wasm?
許多 SO 答案使用await Task.Delay(1)
來解決 Blazor (wasm) 中的各種異步渲染問題。 我什至在我自己的代碼中發現了很多地方這樣做“讓它工作”。
然而,它總是作為事實陳述,沒有徹底的解釋,而且我在文檔中也找不到這種技術。
一些問題:
await Task.Delay(1)
- 我什么時候使用這種技術,用例是什么?Task.Delay(1)
和Task.Yield()
之間有什么區別嗎?為什么使用 await Task.Delay(1) - 我什么時候使用這種技術,用例是什么?
它使 UI 有機會在代碼中間更新和重繪。
文檔不討論這個(我能找到); 是因為它是黑客攻擊,還是處理用例的合法方式?
這是一個黑客。 但在 Blazor/WASM 的特定情況下(沒有其他 Blazor 或 .NET 運行時),沒有很多其他選項。 如果可能的話,我建議拆分您的邏輯,這樣您的應用程序就不會同時做這么多事情; 但有時這是不可能的(或不容易的)。
Task.Delay(1) 和 Task.Yield() 有什么區別?
取決於瀏覽器的詳細信息,是的。
在 Windows UI 應用程序上, Task.Yield
對此不起作用,因為 UI 消息循環是一個優先級隊列,“運行此代碼”是最高優先級。 因此(同樣,對於 Windows UI 應用程序),這會將方法的 rest 排隊,然后返回到消息循環,然后繼續執行代碼而不是刷新 UI(這是較低優先級的消息)。
對於 Blazor/WASM, Task.Yield
是否有效取決於其(隱式)消息循環的瀏覽器實現。 如果它具有類似的優先級隊列,那么您最終會遇到與 Windows UI 相同的問題,其中Task.Yield
確實屈服於消息循環但不會耗盡它。
在所有平台上, Task.Delay(1)
實際上都會排隊一個計時器回調,這通常足以在代碼繼續運行之前處理一些 UI 更新。
下面是我和Henk Holterman
回答的問題的鏈接,他在回答中使用await Task.Delay(1);
運行代碼,看看區別,例如,使用await Task.Delay(1);
導致重新渲染組件兩次,等等。
就是使用await Task.Delay(1);
必要的? 絕對不。 這是一種不好的做法,不僅會導致組件的第二次重新渲染,而且可能會導致復雜代碼出現微妙的問題。 Blazor 提供了一個生命周期方法列表,您可以捕獲並使用這些方法來提供所需的解決方案。 請不要黑客攻擊。 從長遠來看,這可能會非常昂貴。 創建優雅的代碼,而不是黑客...
下面的代碼片段描述了一個使用Task.Delay,
展示了一個帶有標題為“保存”的按鈕元素的頁面,要求是在用戶之后立即將標題的文本更改為“正在保存...”在數據存儲中保存員工記錄期間單擊按鈕。 如果您知道Task.Delay,
請告訴我。
@page "/"
<div>
<button class="btn btn-primary"
@onclick="Save">@caption</button>
</div>
@code
{
private string caption = "Save";
private async Task SaveEmployee()
{
// Simulate saving an employee's record in database...
// I use System.Threading.Thread.Sleep instead of a loop
// with millions of iterations.
System.Threading.Thread.Sleep(3000);
// Retruns completed task
await Task.CompletedTask;
}
private async Task Save()
{
caption = "Saving...";
// Renders here automatically after calling Task.Delay()
await Task.Delay(1000);
await SaveEmployee();
caption = "Save";
// Renders here automatically when SaveEmployee()
//complete
}
}
另一方面,下面的代碼片段演示了如何不使用Task.Delay,
並提供了一個優雅的解決方案,這當然不是 hack,它的額外優點是它會導致組件的單一渲染Task.Delay
涉及第二次渲染,請注意...
注意:下面的代碼是對這個問題的回答
<div @ref="ReferenceToDiv" id="select-@Id" style="background-color: red; width:300px; height: 300px">
</div>
@code
{
ElementReference ReferenceToDiv;
// As you can see, you should call the "adjustPosition" method from the
// `OnAfterRenderAsync` method to ensure that the div element has been
// rendered. DO Not Re-render In Vain. That is, do not use
// await Task.Delay(1); to re-render your component
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (opened)
{
await jsModule.InvokeVoidAsync("adjustPosition", ReferenceToDiv);
}
}
public void OnClick()
{
opened = !opened;
}
}
export function adjustPosition(element) {
// Should return 300px
console.log($(element.style.width);
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.