环境 Blazor Net8.0 + FreeSql + Bootstrap Blazor 组件

以下都是自己瞎琢磨的和官网资料搬运,肯定有不少错漏和不合理的地方,非常希望各位大佬评论区给我建议和意见.

1. 组件化需要提升渲染性能的组件,例如触摸屏显示每个商品下单数量的商品列表

避免不必要地呈现组件子树, 执行一些初始化渲染后设置按需渲染, 外部控制按需渲染参数


//按需渲染
[Parameter]
public bool RenderQuantity { get; set; } = true; protected override bool ShouldRender() => RenderQuantity; protected override void OnAfterRender(bool firstRender)
{
if (firstRender)
{
//执行一些初始化渲染后设置按需渲染 你的初始化渲染(); StateHasChanged();
RenderQuantity = false;
}
} protected override async Task OnParametersSetAsync()
{
if (RenderQuantity)
{
_ = Task.Run(async () =>
{
await Task.Delay(500);
RenderQuantity = false;
});
}
}

调用的页面,添加 RenderQuantity 控制渲染数量变化时机. 避免 StateHasChanged() 执行后渲染子组件.

<OrdersMenuList OrderID="@OrderID"
RenderQuantity="@RenderQuantity"
Refresh="@RefreshOrdersMenuList"
/> private bool RenderQuantity { get; set; }

2. API和UI分离: 例如更新订单数量,操作内存数据渲染到UI,不要等待后台查询订单详单列表后在刷新UI. 异步执行后台服务更新订单数量.

UI 更新数量

Task UpdateQuantity(string userCode, int thisQuantity= 1)
{
//更新订单数量,操作内存数据,不查询数据库,提高性能. API和UI分离
var itemOrdersMenu = OrdersMenu.Where(a => a.UserCode == userCode).FirstOrDefault();
if (itemOrdersMenu != null)
{
itemOrdersMenu.Quantity = thisQuantity;
RenderQuantity = true;
} _ = Task.Run(async () =>
{
//更新订单数量,返回合计
var newOrderdetailsDto = DataService.UpdateQuantity(userCode,thisQuantity);
if (newOrderdetailsDto.ForceQuantity!=null)
{
//处理脏数据问题,更新订单数量为强制数量
item.Quantity = newOrderdetailsDto.ForceQuantity.Value; if (itemOrdersMenu != null)
{
itemOrdersMenu.Quantity = newOrderdetailsDto.ForceQuantity;
RenderQuantity = true;
}
await InvokeAsync(StateHasChanged);
}
});
return Task.CompletedTask;
}

Tips: 对于长时间不操作的订单界面,例如收银台桌面程序(Blazor/Blazor Hybird), 可以设置一个 UI 更新数量定时器, 例如间隔5分钟重新刷新整页.

3. 脏数据: 因为是多终结点程序,不可避免存在脏数据问题. 不更新菜单列表情况下,比对订单数量,更新订单数量.

4. 服务端不要直接更新订单数量,改为原子操作, 采用 a.Quantity = a.Quantity + thisQuantity 方式

服务端 DataService.UpdateQuantity 方法:

fsql.Update<ResOrderDetails>()
.Set(a => new ResOrderDetails()
{
Quantity = a.Quantity + thisQuantity
})
.Where(a => a.OrderID == orderID && a.UserCode == userCode)
.ExecuteAffrows();

5. Button 尽可能使用 OnClickWithoutRender 方法: 点击按钮时触发此事件并且不刷新当前组件,用于提高性能时使用.

6. 使用 CascadingValue 组件具有可选的 IsFixed 参数

  • 如果 IsFixed 为 false(默认值),则级联值的每个接收方都会将订阅设置为接收更改通知。 由于订阅跟踪,每个 [CascadingParameter] 的开销大体上都要比常规 [Parameter] 昂贵。

  • 如果 IsFixed 为 true(例如,),则接收方会接收初始值,但不会将订阅设置为接收更新。 每个 [CascadingParameter] 都是轻型的,并不比常规 [Parameter] 昂贵。

如果有大量其他组件接收级联值,则将 IsFixed 设置为 true 可提高性能。 只要有可能,就应将级联值的 IsFixed 设置为 true。 当提供的值不会随时间而改变时,可以将 IsFixed 设置为 true。

在组件将 this 作为级联值传递时,也可以将 IsFixed 设置为 true:

<CascadingValue Value="this" IsFixed="true">
<SomeOtherComponents>
</CascadingValue>

7. 不要过快触发事件

某些浏览器事件极频繁地触发。 例如,onmousemove 和 onscroll 每秒可以触发数十或数百次。 在大多数情况下,不需要经常执行 UI 更新。 如果事件触发速度过快,可能会损害 UI 响应能力或消耗过多的 CPU 时间。

请考虑使用 JS 互操作来注册不太频繁触发的回调,而不是使用快速触发的本机事件。 例如,以下组件显示鼠标的位置,但每 500 毫秒最多只能更新一次:

@implements IDisposable
@inject IJSRuntime JS <h1>@message</h1> <div @ref="mouseMoveElement" style="border:1px dashed red;height:200px;">
Move mouse here
</div> @code {
private ElementReference mouseMoveElement;
private DotNetObjectReference<MyComponent>? selfReference;
private string message = "Move the mouse in the box"; [JSInvokable]
public void HandleMouseMove(int x, int y)
{
message = $"Mouse move at {x}, {y}";
StateHasChanged();
} protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
selfReference = DotNetObjectReference.Create(this);
var minInterval = 500; await JS.InvokeVoidAsync("onThrottledMouseMove",
mouseMoveElement, selfReference, minInterval);
}
} public void Dispose() => selfReference?.Dispose();
}

相应的 JavaScript 代码会注册用于鼠标移动的 DOM 事件侦听器。 在此示例中,事件侦听器使用 Lodash 的 throttle 函数来限制调用速率:

<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js"></script>
<script>
function onThrottledMouseMove(elem, component, interval) {
elem.addEventListener('mousemove', _.throttle(e => {
component.invokeMethodAsync('HandleMouseMove', e.offsetX, e.offsetY);
}, interval));
}
</script>

8. 使用缓存

private ConcurrentDictionary<TabItem, bool> LazyTabCache { get; } = new();

private RenderFragment RenderTabItemContent(TabItem item) => builder =>
{
if (item.IsActive)
{
var content = _errorContent ?? item.ChildContent;
builder.AddContent(0, content);
_errorContent = null;
if (IsLazyLoadTabItem)
{
LazyTabCache.AddOrUpdate(item, _ => true, (_, _) => true);
}
}
else if (!IsLazyLoadTabItem || item.AlwaysLoad || LazyTabCache.TryGetValue(item, out var init) && init)
{
builder.AddContent(0, item.ChildContent);
}
};
private RenderFragment? _errorContent;
private static readonly ConcurrentDictionary<Type, UrlValueConstraint> _cachedInstances = new();

if (!_cachedInstances.TryGetValue(targetType, out result))
{
result = Create(targetType);
if (result is null)
{
return false;
} _cachedInstances.TryAdd(targetType, result);
}

学习资料

Blazor 性能最佳做法

按需渲染,手动管理 UI 刷新

Blazor/Hybird 触屏下单程序调优笔记的更多相关文章

  1. 【Spark深入学习 -14】Spark应用经验与程序调优

    ----本节内容------- 1.遗留问题解答 2.Spark调优初体验 2.1 利用WebUI分析程序瓶颈 2.2 设置合适的资源 2.3 调整任务的并发度 2.4 修改存储格式 3.Spark调 ...

  2. Perf -- Linux下的系统性能调优工具,第 1 部分 应用程序调优的使用和示例 Tracepoint 是散落在内核源代码中的一些 hook,一旦使能,它们便可以在特定的代码被运行到时被触发,这一特性可以被各种 trace/debug 工具所使用。Perf 就是该特性的用户之一。

    Perf -- Linux下的系统性能调优工具,第 1 部分 应用程序调优的使用和示例 https://www.ibm.com/developerworks/cn/linux/l-cn-perf1/i ...

  3. 17-MySQL DBA笔记-应用程序调优

    第17章 应用程序调优 本章将主要讲述应用程序调优的一些方法和步骤,应用程序调优的领域很广,本章主要关注的是涉及数据库方面的调优. 在进行性能分析之前,我们先要熟悉应用的角色,它是什么版本的,做什么的 ...

  4. Java性能调优笔记

    Java性能调优笔记 调优步骤:衡量系统现状.设定调优目标.寻找性能瓶颈.性能调优.衡量是否到达目标(如果未到达目标,需重新寻找性能瓶颈).性能调优结束. 寻找性能瓶颈 性能瓶颈的表象:资源消耗过多. ...

  5. [转]【JVM】调优笔记2-----JVM在JDK1.8以后的新特性以及VisualVM的安装使用

    [From]https://www.cnblogs.com/sxdcgaq8080/p/7156227.html               隔壁的,加个引用做书签! [JVM]调优笔记2-----J ...

  6. 【JVM】程序调优

    现实企业级Java开发中,有时候我们会碰到下面这些问题: OutOfMemoryError,内存不足 内存泄露 线程死锁 锁争用(Lock Contention) Java进程消耗CPU过高 .... ...

  7. 【JVM】调优笔记2-----JVM在JDK1.8以后的新特性以及VisualVM的安装使用

    一.JVM在新版本的改进更新以及相关知识 1.JVM在新版本的改进更新 图中可以看到运行时常量池是放在方法区的 1.1对比: JDK 1.7 及以往的 JDK 版本中,Java 类信息.常量池.静态变 ...

  8. 【JVM】调优笔记1-----堆栈概念的对碰

    关于JVM的工作原理以及调优是一个向往已久的模块,终于有幸接触到:http://pengjiaheng.iteye.com/blog/518623 那就顺着这个思路,来梳理一下自己看到后的结论和感想. ...

  9. Hive调优笔记

    Hive调优 先记录了这么多,日后如果有遇到,再补充. fetch模式 <property> <name>hive.fetch.task.conversion</name ...

  10. redis性能调优笔记(can not get Resource from jedis pool和jedis connect time out)

    对这段时间redis性能调优做一个记录. 1.单进程单线程 redis是单进程单线程实现的,如果你没有特殊的配置,redis内部默认是FIFO排队,即你对redis的访问都是要在redis进行排队,先 ...

随机推荐

  1. Python数据库编程全指南SQLite和MySQL实践

    本文分享自华为云社区<Python数据库编程全指南SQLite和MySQL实践>,作者: 柠檬味拥抱. 1. 安装必要的库 首先,我们需要安装Python的数据库驱动程序,以便与SQLit ...

  2. KingbaseES V8R6 集群运维案例--备库timeline not contain minimum recovery point故障

    ​ 案例现象: KingbaseES V8R6集群备库启动后,加入集群失败,sys_log日志信息提示,如下图所示: 适用版本: kingbaseES V8R6 一.问题分析 在timeline对应的 ...

  3. #点分治,树状数组#洛谷 5311 [Ynoi2011] 成都七中

    题目 给你一棵 \(n\) 个节点的树,每个节点有一种颜色,有 \(m\) 次查询操作. 查询操作给定参数 \(l\) \(r\) \(x\),需输出: 将树中编号在 \([l,r]\) 内的所有节点 ...

  4. #背包,位运算#洛谷 3188 [HNOI2007]梦幻岛宝珠

    题目 分析 既然对于每个\(w_i\)都能被分解为\(a*2^b\), 那么考虑维护关于\(b\)的背包,再将关于\(b\)的背包统计为关于\(b+1\)的背包 代码 #include <cst ...

  5. go~在阿里mse上使用redis.call

    相关依赖 github.com/higress-group/proxy-wasm-go-sdk github.com/alibaba/higress/plugins/wasm-go 标准的redis ...

  6. netty系列之:在netty中实现线程和CPU绑定

    目录 简介 引入affinity AffinityThreadFactory 在netty中使用AffinityThreadFactory 总结 简介 之前我们介绍了一个非常优秀的细粒度控制JAVA线 ...

  7. 1.NCC算法实现及其优化[基础实现篇]

    NCC算法实现及其优化 本文将集中探讨一种实现相对简单,效果较好的模板匹配算法(NCC) \[R(x,y)= \frac{ \sum_{x',y'} (T'(x',y') \cdot I'(x+x', ...

  8. MogDB/openGauss中merge的语法解析

    MogDB/openGauss 中 merge 的语法解析 近期了解学习了 MogDB/openGauss 中 merge 的使用,merge 语法是根据源表对目标表进行匹配查询,匹配成功时更新,不成 ...

  9. k8s之存储卷local PV

    一.简介 local能够作为PV使用的本地存储卷. local卷插件用于将本地存储设备(如磁盘.分区或目录) 配置为卷. hostPath卷在Pod被重建后可能被调试至其它节点而无法再次使用此前的数据 ...

  10. docker 应用篇————docker-compose[十九]

    前言 简单介绍一下docker compose. 正文 首先进行下载一下. sudo curl -L "https://github.com/docker/compose/releases/ ...