Blazor/Hybird 触屏下单程序调优笔记
环境 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/Hybird 触屏下单程序调优笔记的更多相关文章
- 【Spark深入学习 -14】Spark应用经验与程序调优
----本节内容------- 1.遗留问题解答 2.Spark调优初体验 2.1 利用WebUI分析程序瓶颈 2.2 设置合适的资源 2.3 调整任务的并发度 2.4 修改存储格式 3.Spark调 ...
- Perf -- Linux下的系统性能调优工具,第 1 部分 应用程序调优的使用和示例 Tracepoint 是散落在内核源代码中的一些 hook,一旦使能,它们便可以在特定的代码被运行到时被触发,这一特性可以被各种 trace/debug 工具所使用。Perf 就是该特性的用户之一。
Perf -- Linux下的系统性能调优工具,第 1 部分 应用程序调优的使用和示例 https://www.ibm.com/developerworks/cn/linux/l-cn-perf1/i ...
- 17-MySQL DBA笔记-应用程序调优
第17章 应用程序调优 本章将主要讲述应用程序调优的一些方法和步骤,应用程序调优的领域很广,本章主要关注的是涉及数据库方面的调优. 在进行性能分析之前,我们先要熟悉应用的角色,它是什么版本的,做什么的 ...
- Java性能调优笔记
Java性能调优笔记 调优步骤:衡量系统现状.设定调优目标.寻找性能瓶颈.性能调优.衡量是否到达目标(如果未到达目标,需重新寻找性能瓶颈).性能调优结束. 寻找性能瓶颈 性能瓶颈的表象:资源消耗过多. ...
- [转]【JVM】调优笔记2-----JVM在JDK1.8以后的新特性以及VisualVM的安装使用
[From]https://www.cnblogs.com/sxdcgaq8080/p/7156227.html 隔壁的,加个引用做书签! [JVM]调优笔记2-----J ...
- 【JVM】程序调优
现实企业级Java开发中,有时候我们会碰到下面这些问题: OutOfMemoryError,内存不足 内存泄露 线程死锁 锁争用(Lock Contention) Java进程消耗CPU过高 .... ...
- 【JVM】调优笔记2-----JVM在JDK1.8以后的新特性以及VisualVM的安装使用
一.JVM在新版本的改进更新以及相关知识 1.JVM在新版本的改进更新 图中可以看到运行时常量池是放在方法区的 1.1对比: JDK 1.7 及以往的 JDK 版本中,Java 类信息.常量池.静态变 ...
- 【JVM】调优笔记1-----堆栈概念的对碰
关于JVM的工作原理以及调优是一个向往已久的模块,终于有幸接触到:http://pengjiaheng.iteye.com/blog/518623 那就顺着这个思路,来梳理一下自己看到后的结论和感想. ...
- Hive调优笔记
Hive调优 先记录了这么多,日后如果有遇到,再补充. fetch模式 <property> <name>hive.fetch.task.conversion</name ...
- redis性能调优笔记(can not get Resource from jedis pool和jedis connect time out)
对这段时间redis性能调优做一个记录. 1.单进程单线程 redis是单进程单线程实现的,如果你没有特殊的配置,redis内部默认是FIFO排队,即你对redis的访问都是要在redis进行排队,先 ...
随机推荐
- JDBCUtil 连接MYSQL数据库Java工具类
1 package com.reliable.util; 2 import java.sql.Connection; 3 import java.sql.DriverManager; 4 import ...
- Python flask框架 request.json和request.form的区别
一.fetch请求时,request.json能获取到数据,request.form获取不到数据 1 var data = {'name':'test'}; 2 3 fetch('http://loc ...
- Hadoop_04 验证Hadoop安装成功
[root@master ~]# cd hadoop-2.7.7/[root@master hadoop-2.7.7]# cd etc[root@master etc]# cd hadoop/[roo ...
- C++ 简单实现shared_ptr
共享指针 管理指针的存储,提供有限的垃圾回收工具,并可能与其他对象共享该管理. shared_ptr类型的对象都能够获得指针的所有权并共享该所有权:一旦它们获得所有权,当最后一个所有者释放该所有权时, ...
- axios-api,js结构化定义、调用业务api接口。
axios-api @no-996/axios-api基于 axios 可建立结构化实例的工具,有以下特点: 基于 axios,兼容 axios 的 api,可无缝的迁移使用. 内置了两种常用的请求终 ...
- #轮廓线dp#HDU 1400 Mondriaan's Dream
题目传送门 分析 状压dp会TLE,考虑用轮廓线dp, 设 \(dp[i][j][S]\) 表示现在处理到 \((i,j)\) 这个位置轮廓线上状态为 \(S\) 的情况 二进制位为1表示左边或者上方 ...
- #轮廓线dp,模型转换#洛谷 3226 [HNOI2012]集合选数
题目 问有多少个集合 \(S\) 是 \([1,n]\) 的子集, 并且 \(\forall a,b\in S,a|b\),满足 \(\frac{b}{a}\neq \{2,3\}\) 分析 可以发现 ...
- 基于文件语义实现S3接口语义的注意事项
本文标题中提到的文件语义,指的是POSIX规范. S3指的是AWS提供的对象存储服务以及相关接口.为方便描述,下文中以对象语义替代S3接口语义. 文件语义和对象语义存在比较多的差异. 对象语义不支持文 ...
- 《苏丹的复仇》携手华为HMS生态,实现用户、收入双增长
中国出海中东和北非地区的策略类手游<苏丹的复仇>(Revenge of Sultans,ROS)和华为HMS生态深度合作,为本地用户带来创新游戏体验,成为当地广受欢迎的游戏之一,下载量居应 ...
- 本周三晚19:00Hello HarmonyOS应用篇第7课—分布式应用开发
6月15日19:00 Hello HarmonyOS系列应用篇迎来的本系列直播课的最后一课,将会有怎样的精彩呈现呢? 万物互联的时代已经来临,如果你想运用过往的技术,开发一个有"跨设备操 ...