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

Blazor如何实时渲染未完全加载的预加载数据?

实现Blazor实时渲染已处理数据的最佳方案

针对你提到的大量数据(2000万条)需要等待全部生成后才渲染的问题,核心解决思路是分批生成/加载数据+增量更新UI,结合Blazor的组件状态自动重渲染特性,让用户逐步看到内容。以下是具体可行的方案:

方案一:异步流(IAsyncEnumerable)+ 增量更新

将服务改为返回异步流,边生成数据边传递给前端,页面逐步接收并添加到列表,实时渲染内容。

1. 修改服务方法

把返回类型从Task<WeatherForecast[]>改为IAsyncEnumerable<WeatherForecast>,通过yield return分批返回数据:

public async IAsyncEnumerable<WeatherForecast> GetForecastAsync(DateOnly startDate)
{
    var totalItems = 20000000;
    for (int index = 1; index <= totalItems; index++)
    {
        // 生成单条数据
        yield return new WeatherForecast
        {
            Date = startDate.AddDays(index),
            TemperatureC = Random.Shared.Next(-20, 55),
            Summary = Summaries[Random.Shared.Next(Summaries.Length)]
        };

        // 每生成100条让出线程,给UI更新留时间(平衡实时性与性能)
        if (index % 100 == 0)
        {
            await Task.Yield();
        }
    }
}

2. 修改页面代码

用List<WeatherForecast>存储数据,异步遍历流并逐步添加,按需触发UI更新:

@page "/fetchdata"
@using BlazorApp1.Data
@inject WeatherForecastService ForecastService

<PageTitle>Weather forecast</PageTitle>

<h1>Weather forecast</h1>

<p>This component demonstrates fetching data from a service.</p>

<table class="table">
    <thead>
        <tr>
            <th>Date</th>
            <th>Temp. (C)</th>
            <th>Temp. (F)</th>
            <th>Summary</th>
        </tr>
    </thead>
    <tbody>
        @foreach (var forecast in forecasts)
        {
            <tr>
                <td>@forecast.Date.ToShortDateString()</td>
                <td>@forecast.TemperatureC</td>
                <td>@forecast.TemperatureF</td>
                <td>@forecast.Summary</td>
            </tr>
        }
    </tbody>
</table>

@if (isLoading)
{
    <p><em>Loading more data...</em></p>
}

@code {
    private List<WeatherForecast> forecasts = new();
    private bool isLoading;

    protected override async Task OnInitializedAsync()
    {
        isLoading = true;
        await foreach (var forecast in ForecastService.GetForecastAsync(DateOnly.FromDateTime(DateTime.Now)))
        {
            forecasts.Add(forecast);
            // 每添加100条更新一次UI,避免频繁重渲染导致性能下降
            if (forecasts.Count % 100 == 0)
            {
                StateHasChanged();
            }
        }
        isLoading = false;
        StateHasChanged();
    }
}

方案二:异步流+虚拟滚动(应对超大量数据)

如果数据量达到2000万条,直接渲染所有DOM节点会导致页面严重卡顿,此时结合Blazor的Virtualize组件实现虚拟滚动,只渲染可见区域的行,兼顾实时性与性能。

页面代码示例

@page "/fetchdata"
@using BlazorApp1.Data
@inject WeatherForecastService ForecastService

<PageTitle>Weather forecast</PageTitle>

<h1>Weather forecast</h1>

<p>This component demonstrates real-time data loading with virtual scrolling.</p>

<Virtualize ItemsProvider="@LoadForecastData" Context="forecast">
    <table class="table">
        <thead>
            <tr>
                <th>Date</th>
                <th>Temp. (C)</th>
                <th>Temp. (F)</th>
                <th>Summary</th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td>@forecast.Date.ToShortDateString()</td>
                <td>@forecast.TemperatureC</td>
                <td>@forecast.TemperatureF</td>
                <td>@forecast.Summary</td>
            </tr>
        </tbody>
    </table>
    <Placeholder>
        <p><em>Loading data...</em></p>
    </Placeholder>
</Virtualize>

@code {
    private List<WeatherForecast> loadedForecasts = new();
    private const int TotalItems = 20000000;
    private bool isFullyLoaded;

    private async ValueTask<ItemsProviderResult<WeatherForecast>> LoadForecastData(ItemsProviderRequest request)
    {
        if (isFullyLoaded)
        {
            var paginatedItems = loadedForecasts.Skip(request.StartIndex).Take(request.Count);
            return new ItemsProviderResult<WeatherForecast>(paginatedItems, TotalItems);
        }

        // 每次加载100条数据
        var itemsToLoad = Math.Min(request.Count, TotalItems - loadedForecasts.Count);
        for (int i = 0; i < itemsToLoad; i++)
        {
            var itemIndex = loadedForecasts.Count + 1;
            loadedForecasts.Add(new WeatherForecast
            {
                Date = DateOnly.FromDateTime(DateTime.Now).AddDays(itemIndex),
                TemperatureC = Random.Shared.Next(-20, 55),
                Summary = WeatherForecastService.Summaries[Random.Shared.Next(WeatherForecastService.Summaries.Length)]
            });
            await Task.Delay(1); // 模拟异步生成耗时
        }

        isFullyLoaded = loadedForecasts.Count >= TotalItems;
        var resultItems = loadedForecasts.Skip(request.StartIndex).Take(request.Count);
        return new ItemsProviderResult<WeatherForecast>(resultItems, TotalItems);
    }
}

关键注意事项

  • 控制UI更新频率:避免每添加一条数据就更新UI,建议批量(如100条)更新一次,减少重渲染开销。
  • 虚拟滚动的必要性:超大量数据下必须使用虚拟滚动,否则DOM节点过多会导致页面响应缓慢甚至崩溃。
  • 服务端适配:如果实际场景是从数据库获取数据,可将服务改为分页查询,配合前端增量加载,逻辑与异步流一致。

内容的提问来源于stack exchange,提问作者SolarOsQuiere

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 06:40:22