# trouble / 常见坑总览

> 这个目录是"红旗"的集中清单。开发遇到莫名错误时优先来这里翻一遍。

vjcad 是一个完整的 CAD 引擎，开发中会遇到一些 **跨模块的"看起来无关但其实根因相同"** 的问题。本目录把它们按"症状"分组：

| 症状 | 主页 |
|---|---|
| 启动时画布黑屏 / 实体没进图（`Engine` 未就绪） / `cadView.onLoad` 卡住 | [init-pitfalls.md](init-pitfalls.md) |
| 切页面 / 卸载组件后内存涨 / 事件回调被反复触发 | [event-leak.md](event-leak.md) |
| `EntityAdded` 事件触发了好多次 / `PolylineEnt` 加点时机怪 | [command-event-timing.md](command-event-timing.md) |
| 文档 / 示例 / 源码命名不一致 / 接口签名对不上 | [source-conflicts.md](source-conflicts.md) |

## 通用排查方法

### 1. 看引擎是否初始化完毕

```js
console.log('cadView:', cadView);
console.log('Engine:', Engine);
console.log('pcanvas:', Engine.pcanvas);       // onLoad 前为 null
console.log('mounted:', !!document.getElementById('map'));
```

`Engine` 是静态类，永远不是 `undefined`；`Engine.currentDoc` 在 onLoad 前也不是 `undefined`（懒建的孤儿文档），判断是否就绪看 `Engine.pcanvas` 是否非 `null`，否则去 [init-pitfalls](init-pitfalls.md)。

### 2. 看事件是否被绑了多次

```js
const events = CadEventManager.getInstance();
console.log('监听数:', events.listenerCount(CadEvents.EntityAdded));   // CadEventManager 上没有 _listeners 字段
```

> 用公开的 `listenerCount(event)`；如果某个事件在你 console.log 时已经 > 1，可能是 `useEffect` / 路由切换时没有 `off`。

### 3. 看命令是否被注册多次

```js
console.log('已注册:', CommandRegistry.items.map(i => i.name));
```

`items` 是 `CommandDefinition[]` 静态数组；`regist` 只 push 不去重，执行时 `CommandRegistry.item(name)` 取**第一个**同名定义（先注册者胜出），后注册的不生效；要替换须先 `CommandRegistry.unregist(name)`（每次只删第一个匹配，重复注册过的要循环到返回 `false`）。

### 4. 关键的"先 await 再用"

| 调用 | 必须先 |
|---|---|
| `Engine.xxx` | `await cadView.onLoad()` |
| `cadOverlay.addTo(map)` | `await map.onLoad()` |
| `extractTables()` 等同步 WASM 调用 | WASM 已初始化（`await cadView.onLoad()` 已完成）；`parseSvgToWebcad` 等 async 方法内部会自动 `await this.initWasm()`，无需手动调 |
| `Engine.editor.executerWithOp(cmd)` | `CommandRegistry.regist(cmdDef)` |
| `Engine.patternManager.registerPattern` | `Engine` 已加载 |

### 5. 善用 `writeMessage`

vjcad 在底部命令行打字（HTML）一直是最快的"事件 / 状态"调试通道：

```js
writeMessage('<br/>当前实体数: ' + Engine.currentSpace.items.length);  // BlockDefinition 字段是 items/aliveItems，无 .entities
```

### 6. 仅 dev 时打开详细日志

```js
if (import.meta.env.DEV) {
    // 没有 CadEvents.AnyEvent 通配——要全量监听就自己枚举所有值
    const handlers = {};
    for (const t of Object.values(CadEvents)) {
        handlers[t] = args => console.log('[CAD]', t, args);
        Engine.eventManager.on(t, handlers[t]);
    }
}
```

**生产环境务必关掉**这类全量监听。

## 参考（官方文档 MCP）

- 子页面分别引用了 `vjcad/doc/event/*.md`、`vjcad/doc/guide/*.md`，请按子页面查看
- 通用调试通道（`writeMessage`、`Engine.eventManager.on(CadEvents.XXX, ...)`）见 `vjcad/doc/event/event-usage.md`
