Blazor WASM中Task.WhenAll首次执行卡顿问题求助
Blazor WASM 首次加载时Task.WhenAll卡顿问题
问题场景
在Blazor WASM页面的OnParametersSetAsync生命周期方法中调用异步逻辑,仅使用async/await未使用Task.Wait()或Task.Result。核心逻辑通过Task.WhenAll并行发起多个HTTP请求,出现服务器启动后首次打开页面卡顿的异常现象。
核心代码
SelectNewAddress方法
private async Task SelectNewAddress(AddressElement elem, bool withFillParam) { foreach (var fieldSource in elem.DicFields.Values) { if (fieldSource.Id > 0) address.SelectAddressField(fieldSource); } var lowLevelElementKey = address.DicFields.Where(p => p.Value != null && p.Value.Id > 0).Max(p => p.Key); List<Task> listTasks = new List<Task>(); if (withFillParam) { var t = FillParams(); listTasks.Add(t); } foreach (var kkey in address.DicFields.Keys) { var field = address.DicFields[kkey]; if (field.Id > 0 && field.IdParent > 0) { var t1 = FillDataSourceForElem(field); listTasks.Add(t1); if (kkey == lowLevelElementKey) { var t2 = Task.Run(async () => { if (field.Level >= 1 && field.Level <= 8) { await FillAllChilds(field.Id); } else if (field.Level == 10) { await FillAppartments(field.Id); await FillCarPlaces(field.Id); } else if (field.Level == 11) { await FillRooms(field.Id); } }); listTasks.Add(t2); } } } Console.WriteLine("before when all"); // 此处卡顿,仅在浏览器端服务器启动后首次出现,Blazor MAUI中正常 await Task.WhenAll(listTasks.ToArray()).ConfigureAwait(false); Console.WriteLine("after when all"); InvokeAsync(() => { StateHasChanged(); }); // 以下注释代码可正常运行,但属于即发即弃,无法阻塞界面 //_ = Task.Run(async () => // { // await Task.WhenAll(listTasks.ToArray()); // await InvokeAsync(() => { StateHasChanged(); }); // }); }
HttpClient初始化
HttpClient _client; protected override async Task OnInitializedAsync() { _client = ClientFactory.CreateClient("clientName"); }
调用栈代码
protected override async Task OnParametersSetAsync() { await Initialise(); } private async Task Initialise() { var result = await GetAddressFromDB(); } private async Task<bool> GetAddressFromDB() { try { var elem = await _client.GetFromJsonAsync<AddressElement>($"url?idForm={IdForm}"); if (elem is null) return false; if (elem.Region is null) return false; if (elem.Region.Id <= 0) return false; address.UseMun = elem.UseMun; IsMunHierarchy = address.UseMun; await SelectNewAddress(elem, false); elem.RajonTown.Copy(address.RajonTown); return true; } catch (Exception ex) { // 错误日志 } return false; }
辅助HTTP请求方法
private async Task FillDataSourceForElem(AddressField elem) { List<AddressField> fields = new List<AddressField>(); if (elem.Level >= 1 && elem.Level <= 8) { var rez = await SearchChildsElements(elem.IdParent); fields = rez.Where(p => p.Level == elem.Level).ToList(); } else if (elem.Level == 9) { fields = await GetSteads(elem.IdParent); } else if (elem.Level == 10) { var rez = await GetHouses(elem.IdParent); fields = rez.Select(x => { AddressField b = x; return b; }).ToList(); } else if (elem.Level == 11) { fields = await GetAppartments(elem.IdParent); } else if (elem.Level == 12) { fields = await GetRooms(elem.IdParent); } else if (elem.Level == 17) { fields = await GetCarPlaces(elem.IdParent); } foreach (var fieldChild in fields) { address.AddAddreesFieldInSameLevel(fieldChild); } } private async Task<List<AddressField>> SearchChildsElements(long idParent) { List<AddressField> result = null; try { result = await _client.GetFromJsonAsync<List<AddressField>>($"url?id={idParent}&useMun={_isMunHierarchy}"); } catch (Exception ex) { // 错误日志 } if (result is null) return new List<AddressField>(); return result; }
异常现象
- 服务器启动后首次打开页面,
await Task.WhenAll(listTasks.ToArray())处卡顿;关闭页面重新打开则恢复正常 - 相同代码在Blazor MAUI中运行无异常
- 添加
ConfigureAwait(false)后仍无法解决卡顿 - 改用“即发即弃”方式调用
Task.WhenAll可正常运行,但无法阻塞界面等待操作完成 - 移除并行任务改为逐个
await调用时,会在随机的await _httpClient.GetAsync()处卡顿 - 浏览器F12调试可见请求已发送但处于等待状态,服务器端控制器方法已返回结果
解决方法
在Blazor WASM中避免使用多任务并行处理HTTP请求,禁用额外的Task.Run及并行任务逻辑后,卡顿现象消失。
补充说明:Task.Run在Blazor WASM中仅适用于处理CPU密集型任务,对于IO密集型任务(如HTTP请求),直接异步调用即可,无需额外封装到Task.Run中;并行发起IO请求可能在首次加载时引发线程调度或网络请求队列阻塞问题。
内容的提问来源于stack exchange,提问作者Sergey
相关产品推荐
相关产品推荐

