可视化平台项目面试题整理
可视化平台项目面试题整理
根据我的项目简历整理出的面试题。
- 在军工级大数据可视化平台中,面对7*24小时高刷新,如何保证CPU占用率稳定在15%以下。因为我在简历中提到了通过项目优化确保了长效运行零宕机,所以,这道题目对我来说就是如何进行的项目优化。
我的答案如下:
- 渲染层优化:
- 摒弃传统的DOM定时器,改用了
requesAnimationFrame同步屏幕刷新率,rAF会根据显示器的刷新率(60Hz)自动对齐,确保更新操作发生在浏览器重绘之前,避免了不必要的帧丢失和CPU负载抖动。 - 引入虚拟列表( virtual List)技术,仅渲染视口区域内的监测指标;对于海量原始数据,在前端进行数据抽样算法处理,降低渲染压力
- 摒弃传统的DOM定时器,改用了
- 数据处理和计算优化
Web Worker并行计算:利用web worker将复杂的数值转换和坐标计算逻辑从主线程剥离,避免UI阻塞;- 数据抽样算法:针对监控点位过密的情况,在前端进行了数据抽样、降采样处理,减少了Echarts渲染引擎需要绘制的原始点数,从而直接降低CPU指令数。
- 组件封装
- Canvas渲染方式:在Echarts配置中优先选择
render:canvas。在处理大量动态图形时,canvas这种位图渲染方式比维护上万个svg路径的dom树对CPU更友好 - 核心组件复用:在基于React封装可复用的Echarts组件时,可使用
React.memo,避免因父组件的更新导致图表组件无意义更新。
- Canvas渲染方式:在Echarts配置中优先选择
- 防止内存泄漏
- 生命周期销毁:要检查组件销毁的清理逻辑,确保
websocket连接、定时器以及Echarts实例在组件卸载时,彻底释放内存 - 闭包与引用清理:避免因闭包引起的历史数据未被GC(垃圾回收)而导致系统卡顿甚至卡死。
- 生命周期销毁:要检查组件销毁的清理逻辑,确保
-
在面对4k/8k或者更高的军用大屏,如何解决多分辨率适配及高分屏失真问题?
考察的点:对大屏响应式方案的深度理解
-
Scale整体适配:可以通过监听
resize事件,动态计算当前窗口与设计图稿的比例系数,利用transform:scale(radio)对大屏容器进行整体缩放,这样能保证在4k或者8k的情况下UI不失真、不位移 -
Rem细节调整:可以使用postcss-pxtorem插件,确保极端分辨率情况下依然清晰可读。
-
Canvas处理:对高分屏(Redina),会手动处理
devicePixelRadio将Canvas的画布放大n倍再通过css缩小,解决Echarts的图表边缘模糊的问题
-
平台是如何实现7*24小时的高频数据实时推送与展示?
考察的点:考察Websocket稳定性保障及前端缓存处理机制
- 高可靠的Websocket链路:二次封装原生的Websocket,建立“心跳检测”机制监测连接机制,实现“指数退避”算法的断线重连,确保消息100%到达。
- 数据缓冲机制(Buffer):面对毫秒级的高频推送,前端不立即触发重绘,而是先将数据放到一个数组缓冲区,利用定时器批量取出数据,更新状态,减少Reactx虚拟dom的对比频率。
- 虚拟滚动与局部刷新:针对滚动播放的数据列表,采用虚拟列表的技术方案,确保正常运行下DOM的数量是恒定的,避免因DOM堆积导致的内存泄漏和CPU飙升
- 自动化清理:在组件卸载或者异常刷新时,同步调用销毁函数,防止内存溢出。
- 在海量监控点位的拓扑图中,如何解决渲染卡顿与交互延迟
考察的点:对复杂图形引擎的性能调优能力
- 分片渲染:针对初始化耗时事件较长,使用
requestAnimationFrame将节点和边的渲染任务拆分到多个帧中完成,避免主线程长时间阻塞页面 - canvas优化:使用
canvas渲染模式。利用局部渲染,只有在节点移动或缩放影响到的区域才进行重绘。 - Web Worker: 节点位置计算属于CPU密集型任务,将其放到Web Worker中进行,计算完成后再传回坐标渲染
扩展
数据抽样算法:核心算法最大三角形三桶算法LTTB(largest-Triangle-Tree-Buckets),相比简单的等间隔抽样,它能确保波动的极值不被丢失。下面的代码是一个简化的等间隔平均值抽样,下面的代码其实已经适合大多数的监控场景
/*
*@params {Array} data - 原始大数据数组
*@params {number} threshold - 目标采样数,阈值,用户可根据需求自行设置
*@returns {Array} 抽样后的数据
*/
function downsmaple(data,threshold) {
const dataLength = data.length
if (threshold>=dataLength || threshold <= 0) return data
const sampledData = []
//计算每个桶的大小
const bucketSize = dataLength / threshold
for(let i=0;i<threshold,i++){
const start = Math.floor(i* bucketSize)
const end = Math.floor((i+1) * bucketSize)
//提取该区间的数据
const bucket = data.slice(start,end)
//计算y轴的平均值
const avgY = bucket.reduce((sum,p) => sum + p.y,0) / bucket.length
//选取该区间的中间点做代表
sampledData.push({
x:data[Math.floor((start + end) / 2)].x,
y:avgY
})
}
return sampledData
}
代码分析:
- 分桶:我们需要将原始数据(假设10万个数据)按照我们设置的目标数量(1000个)分成1000个桶,每个桶里都包含了100个点。
- 特征提取:我们取每个桶的平均值angy。在实际复杂的业务场景中,我们通常会取最大值或者LTTB来计算保留波峰。
- 降维处理:将处理好的数据交给Echart时,就从10万条数据变成了1000个数据,渲染压力小了100倍,这样CPU的稳定占用率就能在15%左右了。
本文来自博客园,作者:前端加油站,转载请注明原文链接:https://www.cnblogs.com/bllx/p/19686586

浙公网安备 33010602011771号