> **本文回答**：`await cadView.onLoad()` 是异步初始化的同步点；它在 PixiJS 画布创建、WASM 模块加载、字体加载、插件系统初始化、URL 参数处理全部就绪后才 resolve，**之前禁止使用 `Engine`**。

## 一、`onLoad()` 在等什么

> 引自 `vjcad/doc/guide/quick-start.md`：

> `onLoad()` 返回一个 Promise，在以下初始化完成后 resolve：
> - PixiJS 画布创建
> - WASM 模块加载
> - 字体加载
> - 插件系统初始化
> - URL 参数处理（自动打开图纸、激活侧边栏面板等）
>
> 支持的 URL 参数包括 `vcad_mapid`（图纸ID）、`vcad_panel`（激活面板）等。

## 二、最小用法

```js
const { MainView, initCadContainer, Engine, LineEnt, message } = vjcad;

const cadView = new MainView({
  appname: '唯杰CAD',
  version: 'v1.0.0',
  serviceUrl: env.serviceUrl,
  accessToken: env.accessToken,
});

initCadContainer('map', cadView);

// 必须 await
await cadView.onLoad();

// 此时 Engine 才可用
message.info('初始化完成，开始绑定事件和创建实体...');

const line = new LineEnt([0, 0], [100, 100]);
line.setDefaults();
Engine.addEntities(line);
Engine.zoomExtents();
```

MCP 参考：`vjcad/example/basic/02onload.js`。

## 三、为什么必须 await

`onLoad` 前访问 `Engine.*` 的实际行为（并非"全是 undefined"）：

| getter | onLoad 前实际返回 | 风险 |
|---|---|---|
| `Engine.pcanvas` | `null`（`view?.pcanvas ?? null`） | `Engine.addEntities` 内部 `if (!pcanvas) return` ——**静默丢弃不抛错**，实体凭空消失 |
| `Engine.editor` / `Engine.view` / `Engine.trans` | `undefined` / `null` | 访问属性抛 TypeError |
| `Engine.currentDoc` / `currentSpace` / `undoManager` | **懒创建的孤儿 CadDocument**（`activeDocument` getter 自动 new），不是 undefined | 最阴险：调用"能跑"但写进的是脱离视图的文档，`onLoad` 后真文档替换，数据丢失 |
| `Engine.eventManager` | **真单例**（`CadEventManager.getInstance()`，与 onLoad 后同一个） | 无——onLoad 前注册监听**有效**（旧文档"不会注册到真正单例"的说法有误；`resetInstance` 是 `@internal` 仅供测试，MainView 初始化不调它） |

- WASM 模块还没加载就调 `Engine.editor.executerWithOp('LINE')` 会失败。
- 字体没加载完就创建 `TextEnt`，会显示错位或空文字。
- 插件系统未就绪时调用 `PluginManager.getInstance().loadByName(...)` 会丢调用。

## 四、URL 参数自动打开图纸

`onLoad` 内部会处理 URL 上的 `vcad_mapid / vcad_panel / vcad_version / vcad_branch / vcad_patch / vcad_readonly / vcad_tile / vcad_workspace` 等（具体支持详见 `vjcad/doc/file/file-operations.md` 的 "URL 参数自动打开图纸"）。如果你只需要查看图纸，配合 [viewer-mode](viewer-mode.md) 即可省掉自己的 `DrawingManagerService.openDrawing` 调用。

## 五、销毁与重建（`cadView.destroy()`）

vjcad 按"一次一个视图"设计：文档、撤销、命令表、事件管理器都是 `Engine` 上的全局静态状态。弹框 / 路由反复打开 CAD 时，关闭前必须 `await cadView.destroy()`，再次打开重新 `new MainView` + `initCadContainer` + `await onLoad()`：

```js
// 关闭
await cadView.destroy();   // 依次：卸载全部插件 → 释放 Engine.docs 中全部文档 → 销毁画布 → 清理 Engine 静态缓存 → cad-view 移出 DOM
cadView = null;            // 等价写法：await Engine.destroyViewer();

// 再次打开
cadView = new MainView({ /* ... */ });
initCadContainer(hostElement, cadView);   // 也可直接传容器元素
await cadView.onLoad();
```

不 `destroy` 就重建：`Engine` 的静态缓存仍指向已卸载的旧画布，第二次打开"初始化成功但不显示图纸"。同一页面不要同时保留多个 `MainView`（见 [trouble/init-pitfalls](../trouble/init-pitfalls.md) §7）。

MCP 参考：`vjcad/example/basic/07destroyviewer.js`。

## 反例

- `cadView.onLoad()` 没 `await`，紧接着调 `Engine.addEntities(...)` —— **不报错但实体根本没进图**（`pcanvas` 为 null 时静默 return），比报错更难排查。
- ~~在 `onLoad` 之前监听 `eventManager` 事件不会注册到真正的单例上~~ —— 此说法有误：`eventManager` getter 就是 `CadEventManager.getInstance()` 全局单例，onLoad 前注册有效。
- 写成 `await initCadContainer(...).onLoad()`：`initCadContainer` 返回的是 `HTMLElement`（容器元素，同步返回非 Promise），上面没有 `onLoad`；`onLoad` 是 `MainView` 实例方法。

## 参考（官方文档 MCP）

- 文档：`vjcad/doc/guide/quick-start.md`、`vjcad/doc/file/file-operations.md`
- 示例：`vjcad/example/basic/02onload.js`、`vjcad/example/basic/01init.js`
