Vanilla JS UI Race Conditions (VRM vs Live2D)
应对原生 JS 中的 DOM 竞态与乐观更新陷阱
症状
- 界面组件(如侧边栏、HUD)在页面初次加载时由于丢失状态而不显示,但手动交互后又能弹出。
- 界面在开启和关闭之间发生闪烁,或者无法通过代码正确关闭。
- 绑定在 DOM 元素上的事件监听器未能触发。
根本原因
原因 1: 不同模型/模块的 DOM 懒加载时机不一致
- 问题: 在处理跨模型(如 Live2D 和 VRM)或模块化应用时,某些弹窗会在首次点击时才 createElement(懒加载)。
- 为什么发生: 性能优化导致 DOM 并非一上来就在 HTML 里。如果使用固定的 setTimeout(..., 100) 去抓取 DOM 绑定事件,极大概率会面临扑空(DOM 还未生成)。
- 解决方案: 使用自我终结的递归轮询替代死等。
原因 2: 乐观 UI (Optimistic UI) 与底层状态的竞态冲突
- 问题: 用户点击开关后,前端乐观地将按钮置为开启并附带动画,同时向后端发起请求。但在后端返回真实 lag 之前,如果其他组件(如轮询的 App)根据空后端或者默认的错误 DOM 被触发检查,会产生互相覆盖的 BUG。
- 为什么发生: 缺乏统一的单向数据流。
- 解决方案: 在读取源头状态时,判断 UI 是否处于 disabled(加载中)。如果是,则优先信任 gent_ui_v2 缓存的 optimistic 状态或后端缓存 machineFlags,而不是盲目相信刚建立且尚未同步的 DOM 节点。
代码解决方案
More from project-n-e-k-o/n.e.k.o
vrm-springbone-physics
Debugging and fixing VRM SpringBone physics issues in three-vrm, including hair/clothing physics that flies upward, sticks out horizontally, or behaves unnaturally.
693d-camera-interaction
Three.js 中处理 3D 模型拖拽、缩放、边界检测的正确方法。解决鼠标移动与模型移动不同步、缩放后只能看到模型一部分等问题。
64mcp-builder
Guide for creating high-quality MCP (Model Context Protocol) servers that enable LLMs to interact with external services through well-designed tools. Use when building MCP servers to integrate external APIs or services, whether in Python (FastMCP) or Node/TypeScript (MCP SDK).
50webapp-testing
Toolkit for interacting with and testing local web applications using Playwright. Supports verifying frontend functionality, debugging UI behavior, capturing browser screenshots, and viewing browser logs.
49frontend-design
Create distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, artifacts, posters, or applications (examples include websites, landing pages, dashboards, React components, HTML/CSS layouts, or when styling/beautifying any web UI). Generates creative, polished code and UI design that avoids generic AI aesthetics.
49skill-creator
Guide for creating effective skills. This skill should be used when users want to create a new skill (or update an existing skill) that extends Claude's capabilities with specialized knowledge, workflows, or tool integrations.
49