
本文详解如何通过 websocket 接收动态数据,并安全、高效地更新嵌套结构的二维对象数组(如图表数据源),涵盖遍历、赋值、边界检查与错误防护等关键实践。
本文详解如何通过 websocket 接收动态数据,并安全、高效地更新嵌套结构的二维对象数组(如图表数据源),涵盖遍历、赋值、边界检查与错误防护等关键实践。
在实时数据可视化场景中(如监控仪表盘),常需将 WebSocket 接收的 JSON 数据持续写入预定义的二维对象数组结构——例如 mockLineData,它由多个数据系列(series)组成,每个系列包含一个 data 数组(即二维:series → data[]),而每个 data 元素为 { x, y } 对象。
直接使用 for 循环按索引赋值(如原代码中的 mockLineData[i].data[i].y = ...)存在严重风险:
- ❌ 索引越界:
mockLineData[i]或mockLineData[i].data[i]可能不存在; - ❌ 数据错位:
jsonParse[i]['value_state']假设后端按固定顺序推送,但实际 WebSocket 消息结构可能为单条记录或非对齐数组; - ❌ 缺乏容错:未校验
jsonParse类型、data是否为数组、item.data是否存在。
✅ 正确做法是解耦数据接收逻辑与结构更新逻辑,并采用安全遍历 + 映射更新策略:
1. 安全遍历与动态更新
推荐使用 forEach 配合内层遍历,结合明确的数据映射规则。若后端按“同序号系列对应”推送(如 jsonParse 是长度匹配的数组),可这样更新:
myWs.onmessage = function (message) {
let jsonData;
try {
jsonData = JSON.parse(message.data);
} catch (e) {
console.error("Invalid JSON received:", e);
return;
}
// 确保 jsonData 是数组且长度匹配 series 数量
if (!Array.isArray(jsonData) || jsonData.length !== mockLineData.length) {
console.warn("Data length mismatch. Expected:", mockLineData.length, "Got:", jsonData.length);
return;
}
mockLineData.forEach((series, seriesIndex) => {
// 确保 series.data 存在且为数组
if (!Array.isArray(series.data) || series.data.length === 0) return;
const newDataPoint = jsonData[seriesIndex];
if (!newDataPoint || newDataPoint.value_state === undefined) return;
// 更新最新数据点(推荐追加新点,而非覆盖旧点)
const newX = Date.now(); // 或递增计数器 inc
const newY = Number(newDataPoint.value_state);
// ✅ 推荐:追加新数据点(保持时间序列完整性)
series.data.push({ x: newX, y: newY });
// ⚠️ 若必须覆盖最后一个点(如仅维护固定窗口),则:
// if (series.data.length > 0) {
// series.data[series.data.length - 1] = { x: newX, y: newY };
// }
});
};
2. 初始化与类型防护(关键!)
确保 mockLineData 结构健壮,避免运行时错误:
// 初始化时即保证 data 数组存在
export const mockLineData = [
{
id: "ИБП Uвх",
color: tokens("dark").redAccent[200],
data: [] // 显式初始化为空数组,而非仅含一个占位对象
},
// 可扩展其他 series...
];
3. 注意事项总结
-
永远校验输入:
JSON.parse后检查jsonData类型、结构、字段存在性; -
避免硬编码索引:不假设
jsonParse[i]与mockLineData[i]严格一一对应,建议用id字段匹配(如jsonData.find(d => d.id === series.id)); -
数据点管理策略:实时图表通常需追加(
.push())而非覆盖,配合滑动窗口逻辑清理旧数据; -
性能考虑:高频消息下,避免每次重绘前调用
console.log;可批量更新后触发一次渲染; -
状态同步:若
mockLineData被 React/Vue 等框架响应式监听,直接修改.data.push()可能不触发更新,此时需用series.data = [...series.data, newItem]替代。
遵循以上模式,即可构建稳定、可维护的实时二维数据写入流程。










