ondidchangetextdocument 在文档内容任意变更时立即触发,非仅保存时;需过滤scheme、防抖、清理disposable,否则导致卡顿或逻辑错误。

onDidChangeTextDocument 触发时机远比“保存”早得多
这个事件监听的是任意内容变更,不是文件落盘动作。每次按键、删除、粘贴、甚至撤销重做,只要文档内容字符串变了,它就触发——哪怕你刚输了一个字母还没松手。onDidChangeTextDocument 和 onDidSaveTextDocument 完全是两回事,混用会导致逻辑错乱。
常见错误现象:状态栏实时统计字数时疯狂闪烁、自动格式化在输入中途就执行、CPU 占用飙升。根本原因就是没意识到它高频且细粒度。
- 只在
event.contentChanges.length > 0时才处理,跳过空变更(比如光标移动) - 若需防抖(如格式化),自己加
setTimeout+clearTimeout,别依赖事件节流 - 务必检查
event.document.uri.scheme === 'file',避免对设置页、输出面板、调试控制台等非文件文档误操作
为什么不能用 onDidChangeTextDocument 替代保存钩子
因为它的触发不依赖用户是否点击保存按钮或按 Ctrl+S。Git checkout 切换分支、脚本写入文件、甚至其他编辑器修改同一文件,都不会触发它——它只响应 VSCode 编辑器内部的变更行为。
真正需要“保存后执行”的场景(比如构建、上传、校验),必须用 workspace.onDidSaveTextDocument。否则你会遇到:改完代码没保存,插件却提前跑了构建;或者别人用命令行改了文件,你的插件完全无感知。
使用 SoMark 将 PDF、图片(PNG/JPG/BMP/TIFF/WebP/HEIC)、Word、PPT 及其他文档解析为 Markdown 或 JSON,满足各类文档解析需求(如简历等)。
-
onDidSaveTextDocument是唯一可靠的“保存完成”信号 - 它不保证文件已写入磁盘(取决于文件系统和编辑器缓冲策略),但能确保用户明确触发了保存动作
- 若需配合 Git 状态或外部工具变更,得额外监听
workspace.onDidChangeWorkspaceFolders或集成 chokidar-cli
监听前必须做的三件事:过滤、防抖、清理
高频事件下不加约束,轻则卡顿,重则让 VSCode 响应变慢。这不是性能优化建议,而是基本安全线。
- 过滤:用
document.languageId限定语言,比如只处理'typescript'或'json',避免全局监听拖垮所有文件类型 - 防抖:对耗时操作(如全文正则扫描、AST 解析)必须加
setTimeout缓存,且每次新事件进来先clearTimeout - 清理:注册返回的
Disposable必须推入context.subscriptions,否则热重载或禁用插件时监听器残留,导致内存泄漏或重复触发
容易被忽略的边界:多根工作区与只读文档
VSCode 支持多文件夹打开,onDidChangeTextDocument 会跨所有文件夹触发。如果你的插件只关心某个特定项目,得手动比对 event.document.uri.fsPath 是否在目标路径下。
另外,只读文档(如来自 vscode:// 协议、或设置了 readOnly: true 的临时文档)也能触发该事件,但后续调用 document.save() 会失败。这时候直接跳过处理更稳妥。
- 检查
event.document.isDirty可区分“是否未保存”,但它和“是否可编辑”无关 - 判断只读性请用
!event.document.isUntitled && !event.document.uri.scheme.startsWith('vscode') - 多根工作区中,
workspace.getWorkspaceFolder(event.document.uri)可获取所属文件夹,用于差异化逻辑










