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

如何快速获取LocalStorage数据?优化Blazor大量数据读取性能

Blazor 3000+条LocalStorage数据加载与级联传递优化方案

1. 优化LocalStorage序列化与读取性能

大量数据的JSON序列化/反序列化是主要性能瓶颈之一,可通过以下方式优化:

  • 改用System.Text.Json并配置精简序列化规则,忽略空值、大小写不敏感匹配,减少序列化体积
  • 对数据进行压缩存储,降低LocalStorage的读写IO开销

修改GetProducts方法及新增存储逻辑:

// 注入Blazored.LocalStorage的IJsonSerializer和ILocalStorageService
private readonly IJsonSerializer _jsonSerializer;
private readonly ILocalStorageService _localStorageService;

public MainLayout(IJsonSerializer jsonSerializer, ILocalStorageService localStorageService)
{
    _jsonSerializer = jsonSerializer;
    _localStorageService = localStorageService;
}

public async Task GetProducts()
{
    // 读取压缩后的Base64字符串
    var compressedData = await _localStorageService.GetItemAsStringAsync("ItemsCompressed");
    if (!string.IsNullOrEmpty(compressedData))
    {
        // 解压并反序列化
        var bytes = Convert.FromBase64String(compressedData);
        using var decompressor = new GZipStream(new MemoryStream(bytes), CompressionMode.Decompress);
        using var reader = new StreamReader(decompressor);
        var json = await reader.ReadToEndAsync();
        product = _jsonSerializer.Deserialize<List<Product>>(json, new JsonSerializerOptions
        {
            IgnoreNullValues = true,
            PropertyNameCaseInsensitive = true
        });
    }
}

// 首次存储数据时执行压缩(示例)
public async Task SaveProducts(List<Product> products)
{
    var json = _jsonSerializer.Serialize(products, new JsonSerializerOptions { IgnoreNullValues = true });
    using var compressor = new GZipStream(new MemoryStream(), CompressionMode.Compress);
    using var writer = new StreamWriter(compressor);
    await writer.WriteAsync(json);
    await writer.FlushAsync();
    compressor.Position = 0;
    using var ms = new MemoryStream();
    await compressor.CopyToAsync(ms);
    var compressedData = Convert.ToBase64String(ms.ToArray());
    await _localStorageService.SetItemAsStringAsync("ItemsCompressed", compressedData);
}

2. 优化级联值传递,减少变更检测开销

不要传递整个MainLayout实例,直接传递Product列表,并开启IsFixed(如果数据加载后无变更),Blazor会跳过该级联值的变更检测:

修改MainLayout.razor的级联值部分:

<div class="page">
    <NavMenu/>
    <!-- 直接传递Product列表,而非组件实例 -->
    <CascadingValue Value="product" IsFixed="true">
        <main class="margin-page container px-0">
            <article class="px-1">
                @Body
            </article>
        </main>
    </CascadingValue>
</div>

子组件接收时直接注入:

[CascadingParameter]
public List<Product> Products { get; set; }

3. 延迟加载,避免阻塞页面渲染

不在OnInitializedAsync中同步等待数据加载,先渲染页面框架,后台加载数据完成后再更新UI:

修改MainLayout代码:

<div class="page">
    <NavMenu/>
    <CascadingValue Value="product" IsFixed="true">
        <main class="margin-page container px-0">
            @if (isLoading)
            {
                <div class="loading">加载中...</div>
            }
            else
            {
                <article class="px-1">
                    @Body
                </article>
            }
        </main>
    </CascadingValue>
</div>

@code {
    public List<Product> product { get; set; } = new List<Product>();
    private bool isLoading = true;

    protected override async Task OnInitializedAsync()
    {
        // 后台异步加载,不阻塞页面渲染
        _ = LoadProductsAsync();
        await base.OnInitializedAsync();
    }

    private async Task LoadProductsAsync()
    {
        await GetProducts();
        isLoading = false;
        // 通知UI更新
        StateHasChanged();
    }

    // 原GetProducts方法保留
}

4. 内存缓存复用,避免重复读取LocalStorage

将加载后的Product列表存入全局Singleton缓存,后续页面切换无需重复读取LocalStorage:

创建缓存服务:

public class ProductCacheService
{
    public List<Product> Products { get; private set; } = new List<Product>();
    public bool IsLoaded { get; private set; }

    public async Task LoadFromLocalStorage(ILocalStorageService localStorageService)
    {
        if (!IsLoaded)
        {
            var result = await localStorageService.GetItem<List<Product>>("Items");
            if (result != null)
            {
                Products = result;
            }
            IsLoaded = true;
        }
    }
}

在Program.cs注册:

builder.Services.AddSingleton<ProductCacheService>();

修改MainLayout的加载逻辑:

private readonly ProductCacheService _productCache;

public MainLayout(ProductCacheService productCache, ILocalStorageService localStorageService)
{
    _productCache = productCache;
    _localStorageService = localStorageService;
}

private async Task LoadProductsAsync()
{
    await _productCache.LoadFromLocalStorage(_localStorageService);
    product = _productCache.Products;
    isLoading = false;
    StateHasChanged();
}

5. 组件端按需渲染,减少DOM压力

如果子组件需要展示Product列表,使用Blazor内置的Virtualize组件实现虚拟滚动,只渲染可视区域内的条目:

子组件示例:

<Virtualize Items="@Products" Context="product" ItemSize="50">
    <div class="product-item">@product.Name</div>
</Virtualize>

@code {
    [CascadingParameter]
    public List<Product> Products { get; set; }
}

内容的提问来源于stack exchange,提问作者Haneen Al-fakhry

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 08:30:42