diff --git a/src/pages/movement-supervision.vue b/src/pages/movement-supervision.vue index cd24606..da83b9c 100644 --- a/src/pages/movement-supervision.vue +++ b/src/pages/movement-supervision.vue @@ -76,18 +76,25 @@ const monitorScene = async () => { /** * 渲染循环函数。 - * 这个函数会通过 requestAnimationFrame 以浏览器的刷新频率(通常是60fps)被反复调用。 - * 这是实现流畅动画的核心。 + * 通过 requestAnimationFrame 以浏览器的刷新频率被调用。 + * 采用时间分片(Time Slicing)策略,为每一帧的渲染操作设定一个时间预算(frameBudget), + * 避免单帧处理过多数据导致UI阻塞。 */ const renderLoop = () => { - // 检查是否有新的数据需要渲染。如果没有,则本次循环不执行任何操作,节省性能。 - if (latestRobotData.size > 0) { - // 遍历所有待更新的机器人数据 - latestRobotData.forEach((data, id) => { - const { x, y, active, angle, path, isWaring, isFault, ...rest } = data; - // 确保机器人仍然存在于编辑器中 - if (!editor.value?.checkRobotById(id)) return; + const frameBudget = 8; // 每一帧的渲染预算,单位:毫秒。保守设置为8ms,为其他任务留出时间。 + const startTime = performance.now(); + // 在时间预算内,持续处理数据 + while (performance.now() - startTime < frameBudget && latestRobotData.size > 0) { + // 获取并移除 Map 中的第一条数据 + const entry = latestRobotData.entries().next().value; + if (!entry) break; + const [id, data] = entry; + latestRobotData.delete(id); + + const { x, y, active, angle, path, isWaring, isFault, ...rest } = data; + // 确保机器人仍然存在于编辑器中 + if (editor.value?.checkRobotById(id)) { // 更新机器人的非位置属性(如状态等) editor.value?.updateRobot(id, rest); @@ -99,11 +106,11 @@ const monitorScene = async () => { // 如果坐标有效,则刷新机器人在画布上的位置、角度等 editor.value.refreshRobot(id, { x, y, active, angle, path, isWaring, isFault }); } - }); - // 本次渲染完成后,清空数据缓冲区,等待下一批新数据的到来。 - latestRobotData.clear(); + } } + // 请求浏览器在下一次重绘之前再次调用 renderLoop,形成动画循环。 + // 即使本帧没有处理完所有数据,下一帧也会继续处理剩余的数据。 animationFrameId = requestAnimationFrame(renderLoop); };