You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 17:14:50