首页 > 其他分享 >Blazor 通过组件虚拟化提高性能

Blazor 通过组件虚拟化提高性能

时间:2025-01-17 17:22:54浏览次数:1  
标签:虚拟化 项目 Virtualize 渲染 组件 Blazor 加载

了解组件虚拟化如何优化 Blazor 应用程序的渲染性能.

介绍

在使用数据驱动的应用程序时,我们迟早要在列表中呈现数量多得令人难以忍受的项目。作为开发人员,我们总是希望用户界面尽可能清晰,并且只包含执行特定操作所需的数据。

但是,如果产品所有者要求呈现 10000 或 100000 个项目怎么办?如果理由是“客户需要它”怎么办?作为一名优秀的开发人员,我们会想出一个可行的解决方案。

渲染数千或数十万个项目的根本问题是渲染需要时间、占用大量内存,并且通常会让网站感觉很慢。

组件虚拟化是 Blazor 的一项功能,可以帮助我们找到此类场景的解决方案。

没有虚拟化的问题

在实现虚拟化之前,我们首先需要创建一个示例,展示在 Blazor 中渲染数千个项目是什么样子。

考虑以下在屏幕上呈现订单的代码。

<h1>Orders</h1>
@foreach (var order in Orders)
{
    <div style="display:flex;">
        <div style="width: 400px;">@order.Id</div>
        <div>$ @order.Value</div>
    </div>
}

@code {
    public record Order(Guid Id, int Value);

    public IList<Order> Orders { get; set; } = new List<Order>();

    protected override void OnInitialized()
    {
        var random = new Random();
        for (int i = 0; i < 100_000; i++)
        {
            Orders.Add(new Order(Guid.NewGuid(), random.Next(20, 9999)));
        }
    }
}

Order我们定义一个包含Id和属性的对象列表Value。在OnInitialized生命周期方法中,我们创建十万个订单并将它们添加到Orders列表中。

在组件模板中,我们有一个foreach语句来渲染屏幕上的所有项目。在此示例中,我们只div为每个订单渲染三个项目。在更复杂的设置中,这可能是一棵完整的对象树,其中包括更多 HTML 元素。

尽管我们使用了相对简单的 HTML 标记,但在导航到页面时我们已经明显感觉到延迟。此外,由于使用了1.4 GB 的内存,这绝对不是理想的情况。

如何实现虚拟化

Blazor 提供了一个内置Virtualize组件,使虚拟化组件变得简单。最好的部分是:我们可以虚拟化任何东西。无论是另一个 Blazor 组件、简单的 HTML 元素还是两者的混合。

下面的模板代码展示了如何虚拟化上面介绍的示例。

<Virtualize Items="Orders" Context="order">
    <div style="display:flex;">
        <div style="width: 400px;">@order.Id</div>
        <div>$ @order.Value</div>
    </div>
</Virtualize>

该Virtualize组件公开了一些属性。最重要的是Items和Context。我们将要虚拟化的项目列表作为Items属性的参数提供。我们为每个项目提供一个名称作为属性的值Context。

然后我们可以使用组件内的顺序变量Virtualize来定义每个项目的模板。

使用组件虚拟化运行 Blazor 应用程序时,我没有注意到渲染页面时出现延迟。此外, Google Chrome 中的内存消耗已从未使用虚拟化之前的 1.4 GB降至100 MB 。

通过将项目代码包装在 Virtualize 组件中这样简单的事情,我们可以实现快速的页面加载和更少的内存消耗。

它是如何工作的?

您可能想知道它在幕后是如何工作的。很容易假设该Virtualize组件实现分页,这意味着它只加载屏幕上可查看的项目。不幸的是,事情没那么简单。

当我们在方法中初始化项目列表时OnInitialized,我们已经将所有项目提取到内存中。将模板代码包装在Virtualize组件中不会改变这一点。项目仍在内存中。

另一方面,如果没有虚拟化,页面将为div列表中的每个项目呈现一个。

控制渲染行为

滚动时,该Virtualize组件会呈现附加组件,使用户感觉无缝。

该Virtualize组件有一个内部实现,用于决定在屏幕上当前可见的内容之外渲染多少元素。内部算法基于项目的高度及其容器的高度。

我们可以使用Virtualize组件的OverscanCount属性来改变渲染的附加项目数量。

但是,屏幕上只呈现了有限数量的元素。我们可以通过打开开发人员工具并查看元素选项卡来观察这一点。使用虚拟化,我们只能看到有限数量的div元素。

<Virtualize Items="Orders" Context="order" OverscanCount="15">
    <div style="display:flex;">
        <div style="width: 400px;">@order.Id</div>
        <div>$ @order.Value</div>
    </div>
</Virtualize>

我通常会尽可能保留默认值。有时,根据单个项目内容的复杂程度和大小,您需要手动设置OverscanCount属性以更好地控制其渲染行为。

对于我上面的例子,默认实现会渲染大约 15 个附加项目。

延迟加载项目

但是如果加载项目的成本很高怎么办?如果我们只想加载屏幕上实际可见的项目怎么办?是的,这是可能的。

延迟加载使用该ItemsProvider属性而不是组件Items的属性Virtualize。

<Virtualize ItemsProvider="@LoadOrders" Context="order">
    <div style="display:flex;">
        <div style="width: 400px;">@order.Id</div>
        <div>$ @order.Value</div>
    </div>
</Virtualize>

重要提示:我们既可以使用Items包含所有项目的集合的属性,也可以ItemsProvider使用加载项目的方法的属性,但不能同时设置它们。否则,我们将InvalidOperationException在运行时得到一个。

现在我们看一下LoadOrders放置在@codeLazyLoading页面组件部分中的方法。

private ValueTask<ItemsProviderResult<Order>> LoadOrders(ItemsProviderRequest request)
{
    StartIndex = request.StartIndex;
    Count = request.Count;

    StateHasChanged();

    var filteredOrders = Orders.Skip(request.StartIndex)
        .Take(request.Count);

    var result = new ItemsProviderResult<Order>(filteredOrders, Orders.Count());
    return ValueTask.FromResult(result);
}

虚拟化和延迟加载的陷阱

提供的Virtualize组件做了很多工作来减少显示大量数据列表所需的渲染性能。

但是,也有一些限制。例如,所有项目的高度必须相同。否则,Virtualize组件无法计算滚动范围,因此不知道要渲染什么。

此外,如果每 40-50 个项目调用一次昂贵的 API,则会增加很多开销。例如,您可能会有 HTTP 请求,包括每个请求的延迟。有时,最好预先加载所有数据,即使用户需要等到整个数据集下载完毕。

与软件工程中常见的情况一样,此功能并非每次都可用。它更像是工具箱中的附加项。在有意义时使用它,在不合适时使用其他功能。

结论

内置组件允许我们通过仅渲染屏幕上可见的项目Virtualize来高效地渲染大型数据集。该组件使用内部算法来决定一次显示多少个项目。

我们可以使用该Items属性提供预填充的数据列表或ItemProvider延迟加载数据。正如本文所述,这两种方法各有优缺点。

这OverscanCount允许我们控制同时渲染的项目数量。设置此属性有助于根据您的用例调整行为。当使用延迟加载的 API 调用需要很长时间时,请增加此值。渲染简单的内存组件时,请减少此值以提高页面加载性能。

总而言之,内置Virtualize组件可以帮助您编写更高效的 Blazor 应用程序。

Flex布局使用虚拟化

Flex布局使用虚拟化

参考链接

https://www.telerik.com/blogs/blazor-basics-improved-performance-component-virtualization

https://learn.microsoft.com/en-us/aspnet/core/blazor/components/virtualization?view=aspnetcore-9.0

标签:虚拟化,项目,Virtualize,渲染,组件,Blazor,加载
From: https://www.cnblogs.com/densen2014/p/18677409

相关文章

  • GaussDB事务存储组件
    事务存储组件云原生数据库支持透明多写,所有节点对等,每个计算节点都可以读写全部的数据页面,事务在本节点执行,没有分布式事务。每个计算节点都有Localbufferpool,采用Remotememorypool扩展计算节点的内存,在多个计算节点之间共享buffer地址,避免页面在多个计算节点之间传来传去。......
  • GaussDB实时分析组件
    云原生数据库以OLTP为主,同时也支持基于OLTP数据的OLAP需求,如每日报表。在云原生数据库中,DBA可以选择为这部分表创建列存索引。创建完列存索引之后,执行器在做顺序扫描的时候,会自动选择列存索引进行数据的读取,实现快速扫描计算的能力。云原生数据库以行存为基础,数据的增删改都先以......
  • GaussDB关键技术方案_通信组件
    GaussDB关键技术方案_通信组件云原生数据库采用shareddisk架构,各个计算节点对等,计算节点之间通过页面交换实现缓存数据的一致性,为了提高页面传递的效率,需要利用RDMA或UB单边读写的能力;云原生数据库为了管理动态资源,需要对动态资源的owner分配进行加锁,分布式锁管理需要利用原子操......
  • GaussDB多租组件
    云原生数据库支持多租户,通过多租户资源共享,一是降低租户的成本,二是通过共享资源的池化实现租户的资源弹性,提高租户业务的可用性。租户的资源弹性支持两种模式,ScaleUp和ScaleOut。ScaleUp是在单个计算节点上对租户的分配资源进行弹性处理,ScaleOut是在计算节点之间对租户的分配......
  • vue2根据方法名调用方法,vue2根据方法名调用父组件方法
    methods:{dictByItem:function(item,row){letdictElement=this.dict[item.dictName];letfilter=dictElement.filter(i=>i.value===row[item.prop]+'');returnfilter&&filter.length>[0]?filter[0]......
  • Flutter使用FractionallySizedBox组件报错Failed assertion: line 2164 pos 12: 'hasS
    这里从解决方法那里直接给出个有效的方式。就是如果你使用了FractionallySizedBox组件,第一是这个组件只能在固定宽高下或者Row,Flex,Column组件下使用。第二就是这个组件需要在Flexible下使用.结构就是:Row->Flexible->FractionallySizedBox给出简单的代码示例......
  • SpelExpressionParser 是 Spring Expression Language(SpEL)中的一个重要组件,用于解析
    SpelExpressionParser 是SpringExpressionLanguage(SpEL)中的一个重要组件,主要用于解析和评估Spring表达式。以下是关于它的详细解释:主要功能表达式解析:将一个以字符串形式表示的Spring表达式转换为可执行的表达式对象。Spring表达式可以包含变量引用、方法调用、属性......
  • 原生JS实现一个日期选择器(DatePicker)组件
    这是通过原生HTML/CSS/JavaScript完成一个日期选择器(datepicker)组件,一个纯手搓的组件的开发。主要包括datepicker静态结构的编写、日历数据的计划获取、组件的渲染以及组件事件的处理。根据调用时的时间格式参数,可以控制短日期格式或长日期格式。实现效果(短日期格式)实现效果......
  • 深入探索Vue.js 3中基于Composition API的动态组件开发
    在前端开发中,组件是构建用户界面的基础,而Vue.js作为一种流行的前端框架,也提供了灵活强大的组件机制。在本文中,我们将深入探索基于Vue.js3的CompositionAPI,开发一个动态组件加载的技术方案。这项技术对于那些需要高可维护性和按需加载的应用来说尤其重要。什么是动态组件加......
  • GaussDB事务存储组件
    事务存储组件云原生数据库支持透明多写,所有节点对等,每个计算节点都可以读写全部的数据页面,事务在本节点执行,没有分布式事务。每个计算节点都有Localbufferpool,采用Remotememorypool扩展计算节点的内存,在多个计算节点之间共享buffer地址,避免页面在多个计算节点之间传来传去。......