ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

VSCode 文件操作一直等待中?从文件锁到 Watcher 的全面排查与优化

VSCode 文件操作一直等待中?从文件锁到 Watcher 的全面排查与优化 你是不是也在 VSCode 里遇到过这种情景新建一个文件名字敲下去半天不落盘改动几行代码按一下 CtrlS右下角保存状态一直转圈右键删除文件光标转得像风扇标题栏上却挂着等待中。我这些年做编辑器调试和排障这种vscode 增删改查文件一直等待中的卡顿说大不大但确实让人抓狂而且它不像报错那样有红字提示往往连从哪下手都不知道。这篇文章就围绕这个现象把常见原因、排查方法和配置优化一次性讲透适合日常用 VSCode 写代码、做笔记、管文件的所有人尤其是被保存转圈文件删不掉折磨过的朋友。1. 现象还原VSCode 里的一直等待到底长什么样说实话等待中这三个字在 VSCode 里通常不会弹个对话框告诉你我在等文件锁而是悄无声息地让整个编辑器处于半瘫痪状态。我刚接触这个需求的时候第一反应是用户的机器太老或者目录太大可细聊下来发现根本不是那么回事。问题的表象五花八门但本质上都是同一个底层链路出了问题。1.1 几种典型的卡死场景我在实际使用和帮人排错过程中遇到的一直等待中大致可以归纳成五类每一类的表象都不同但核心都是文件系统操作没法正常完成新建文件没反应。按完 CtrlN 或者右键选 New File输入框在编辑器里闪烁输入了名字回车文件却迟迟不落盘资源管理器里也刷不出来。保存一直转圈。改完代码按 CtrlS状态栏右侧那个保存图标一直转文件内容明明已经写进去了但 VSCode 还在排队这时候你再点别的文件新的文件也打不开。删除提示权限/占用。右键删除一个文件或者把某个目录拖进回收站系统弹出文件正在被使用或者干脆无响应命令行里报 EBUSY / EPERM。打开文件无限加载。双击打开一个文档标签页一直显示加载中同时打开另一个文件也一样整个窗口就像被掐住了脖子。全局无响应但 UI 还活着。鼠标能动菜单能点但标题栏一直显示正在等待文件操作。这种最坑因为你不确定到底在等什么也不敢乱点。这些情况的共性是什么都是文件操作层没有及时返回结果。VSCode 不是单线程工具它有一个专门的文件系统抽象层去调度所有文件事件只要这一层被堵住你用鼠标点哪儿都白搭。1.2 为什么说增删改查会一起卡你可能觉得增删改查更像数据库专有名词但放到编辑器里其实完全对应新建对应 create删除对应 delete编辑保存对应 update跳转、搜索、打开对应 read。VSCode 底层有一个统一的文件系统抽象层FileSystem Provider不管是本地文件、远程 SSH、还是挂载的 WSL 目录所有操作都要经过它。我做一个不太严谨但特别好懂的生活化类比这个抽象层就像物业的一站式窗口所有住户的水电煤申请都要从前台走。只要有一个住户的申请卡住了后面的所有住户都得排队等着哪怕你的申请只是换灯泡这种小事。VSCode 的文件系统层也一样只要任何一个未完成的 IO 操作没结束后台的增删改查全都得排队表现出来就是等待中。很多人在这个阶段容易走弯路以为是某个文件坏了或者以为要重装 VSCode。实际上绝大多数问题都出在有一个文件操作没有正常结束把整条流水线堵死了。理解这一点排查思路就清晰了——你需要的不是重装而是把卡住的那个操作找出来。2. 根源拆解文件增删改查为什么会一直等等你把等待中当成一个整体现象去看时就会发现底层原因可以被拆开。我习惯把这些原因按文件锁、会话残留、监视器压力、扩展拖累、远程通道五个方向去归类绝大多数案例都能覆盖。这五个方向不是孤立的有时候两个甚至三个因素叠加在一起让问题显得特别难缠。2.1 增文件时卡住的常见原因新建文件本身是一个轻量操作正常情况下几百毫秒就完成卡住通常意味着目标目录不可写或者目录被某个后台进程锁住了。举几个真实例子。在 Windows 上如果另一个程序杀毒软件、同步盘、甚至资源管理器正在扫描这个目录新建文件就会等扫描结束。还有一点特别容易忽略如果当前工作区是从一个不存在的路径打开或者路径中含特殊字符空格、中文、~文件系统插件可能一直重试。还有一种情况是自动保存的热退出Hot Exit机制——VSCode 在异常关闭后会恢复上次未保存的缓冲区。如果这些缓冲区对应的文件已经被移动或删除恢复过程就会卡住而新建操作也要等恢复结束。我遇到过一个用户连续一周每天开机都看到 VSCode 弹恢复窗口他每次都点取消但后台进程还在反复尝试读取那批已不存在的文件导致新建文件永远出不来。2.2 删文件时卡住的原因删除操作失败最常见是三因素文件被编辑器自身占用比如你在几个标签页里同时打开了同一个文件还有未保存的编辑被别的进程占用本地服务正在读写、杀毒软件实时防护、索引服务在扫描或者是在远程环境下权限不足。前面两种在 Windows 上特别典型。Windows 对文件锁的粒度没有 Linux 那么宽松一个进程只要以独占模式打开了文件你这边怎么删都删不掉。我见过最离谱的一次是一个前端项目里删除node_modules下的某个子目录卡了整整 5 分钟最后发现是有个残留的 node 服务进程一直在读那个目录。第三个原因容易被忽视VSCode 的某些扩展会主动监听文件变化。如果你装了 Live Server、ESLint、自动格式化这类扩展删除文件时它们会先拿到事件要执行清理逻辑。一旦某个扩展的回调没有返回删除操作就会挂起而且这个挂起会顺着文件系统事件队列传染给别的操作。这也是为什么有时候你删一个小文件整个窗口都卡住的原因。2.3 改文件时一直转圈的原因保存文件时转圈是最常见、也最多人跑来问我的一个问题。这里有个很多人不知道的机制VSCode 保存文件不是直接把内容写进磁盘而是先写到一个临时文件然后做替换原子写写完还要触发一次文件监视来通知扩展。整个链路里只要有一环慢视觉上就是一直在等待。具体来说可能有这几个环节目标目录磁盘 IO 慢或故障。机械盘碎片多、NAS 网络延迟高、云盘目录同步繁忙都会拖慢写盘。自动保存files.autoSave开关开着。每次输入都触发写盘写盘任务一多后续操作就开始排队。格式化或保存时运行任务。你先打开了保存时格式化editor.formatOnSave又配置了保存后运行 build 任务每次 CtrlS 都会先跑一遍格式化加编译中间任何一步卡住保存状态就一直转。文件被设置了只读但用户没注意到。VSCode 会反复尝试写权限直到超时表现就是转圈很久才弹错误。2.4 查文件时卡住的原因这里的查不仅是打开文件看内容还包括全局搜索、跳转定义、终端 grep。搜索和跳转涉及全目录扫描一旦某些目录里塞着巨大的 node_modules、.git 对象、构建产物扫描起来非常耗时。如果files.watcherExclude没有把这些目录排除VSCode 的 File Watcher 就会在后台不停遍历导致打开文件这个查询操作也排队。另外如果你开了多个工作区窗口每个窗口各自维护一套 watcher内存和文件句柄快速上涨整个编辑器就开始等。排除完这些大部分人卡住的元凶往往就浮现了一个异常扩展里的事件监听器死循环或者过期的未保存会话在后台反复重试。下面进入可执行的排障流程。3. 硬核排障从简单到复杂的修复路径我处理这类问题有一套固定的由简到繁的顺序因为越简单的操作代价越小也更安全。以下步骤不需要全都做走到哪一步解决了就停在哪一步。注意每改一个地方就实测一次不要一次改一大堆配置不然你根本不知道是谁起了作用。3.1 第一步缩小范围判定是全局还是单目录遇到一直等待第一件事不是改配置而是先做对照组。用当前窗口在命令行里敲code .运行然后再打开任意一个磁盘上干净的空目录最后把当前工作区关闭File Close Workspace看文件操作是否恢复。我一般会做三组判断如果空目录正常、当前目录卡死优先怀疑该目录下有异常路径空格、符号链接、超深层级。如果所有目录都卡再看是否是扩展或配置导致的全局问题。如果关掉工作区后文件操作就恢复说明是某个扩展绑定了工作区级事件不是磁盘问题。这一步能让排查范围瞬间缩小一半以上也有利于后面发帖求助时描述问题。我试过很多次光这一步就能解决三成用户的困惑——他们把当前目录的问题错当成了VSCode 整体的问题。3.2 第二步锁定可疑进程与文件占用范围缩小后第二步就是看底层到底是谁在占用文件。Windows 下我推荐用进程资源监视器Process Explorer外部工具和系统自带资源监视器resmon配合。如果不想装外部工具也可以用命令行工具定位但注意相关工具要从官方渠道获取。实际操作中不借助外部工具时最简单的办法是把可疑目录拷贝一份到别处从新位置打开 VSCode看操作是否正常。杀掉非必要的同步盘、杀软或 NAS 客户端进程后再试一次。如果用了 WSL/SSH 远程插件直接重启插件对应的远程服务命令面板里搜Reload Window。对 Linux/macOS可以用lsof看谁打开了文件# 查看哪个 PID 占用了文件 lsof /path/to/file.txt多数情况下你能看到一个不该在这里的进程——比如旧的命令行窗口、崩溃后遗留的 node 服务进程、甚至之前没关干净的调试会话。把这些进程处理掉文件操作马上恢复。我印象最深的是有个用户本地起了个json-server它把整个项目目录都监控起来了VSCode 和它抢文件锁抢不过就一直等。杀掉那个服务问题瞬间消失。3.3 第三步处理 Hot Exit 残留与未保存会话宏大的重装步骤先放一放我更建议你先处理未保存会话。VSCode 每次异常关闭都会把未保存内容存到一个备份目录下次启动时恢复。如果这个恢复环节卡了你的增删改查都会排队。处理方法很简单打开命令面板CtrlShiftP输入 Developer: Open Backup Storage Folder打开备份目录。把这个目录里工作区对应的备份文件备份一份到外部先保留确认没问题再删。关闭 VSCode 后把备份目录里无用或损坏的*.json、临时文件清掉。重启 VSCode看是否恢复。这里有个经验之谈备份目录在异常退出后容易产生几十上百个文件而 VSCode 启动时会等待恢复编辑器这个异步任务结束。如果你在恢复过程中点了别的地方整个界面看起来就像卡死。直接清掉旧的备份能解决大量打开就等待的问题。但注意清备份等于放弃未保存的内容操作前一定确认那些内容你已经不需要了或者已经手动另存过了。3.4 第四步调整文件监视与自动保存策略排除了占用和恢复残留后就要看 File Watcher 和自动保存。VSCode 默认会监视工作区里几乎所有文件的变化以支持版本控制标记、错误提示、自动刷新等功能。一旦目录结构复杂监视器资源吃紧新操作的客户端就开始排队。我建议把下面这段配置加进settings.json打开命令面板输入 Preferences: Open User Settings (JSON){ files.watcherExclude: { **/.git/objects/**: true, **/.git/subtree-cache/**: true, **/node_modules/**: true, **/dist/**: true, **/build/**: true }, files.autoSave: off, search.useIgnoreFiles: true, search.followSymlinks: false }这段配置的核心作用是把 node_modules、dist、build 等目录排除出监视范围减少 watcher 压力同时关闭自动保存避免每次停顿都触发写盘。search.useIgnoreFiles让搜索跳过被 gitignore 忽略的目录search.followSymlinks关闭符号链接跟随这两个选项对搜索、定义跳转的提速非常明显。我实测过一个包含 5 万多个文件的大型 monorepo加了这些配置后打开文件从卡顿变成可以接受如果再配上**/.cache/**、**/temp/**也一起排除体感会更好。但注意别把所有目录都排除否则代码提示和版本控制更新也会变慢得不偿失。3.5 第五步扩展排查与配置重置如果前三步都没效果扩展的嫌疑就直线上升。扩展导致等待中最常见的原因是扩展在onWillSave或onDidChangeTextDocument等事件里执行了耗时回调同步遍历大文件、请求网络、编译或者两个扩展互相等待锁。排查时我最推荐二进制排除法命令面板输入 Developer: Disable All Extensions。重启 VSCodeReload Window。一个个启用扩展每启用一个就重复几次文件增删改查操作直到定位到问题扩展。对可疑扩展再去看它的日志或者用命令面板里的 Developer: Show Logs 查看扩展宿主进程日志。另外要考虑配置被破坏的情况。你可以把用户设置里可疑的配置项临时移除或者在启动时带上--disable-extensions参数验证# 临时禁用所有扩展启动 code --disable-extensions .如果这样启动后一切正常那就可以确认问题在扩展或扩展与配置的交互上。此时建议把 VSCode 升级到最新稳定版因为文件系统相关的 bug 在历史版本里出现过多次官方修复速度也很快。我见过一个用户用的还是两年前的版本升级之后连等待中三个字都很少看到。3.6 第六步远程/共享文件场景的专项处理很多人是在 WSL、SSH、Docker 容器里写代码时遇到等待中的。这时候本地和远端走的是两个进程文件操作要先经过本机到远端的协议通道。通道一旦断连或抖动编辑器里的文件操作就会进入长时间等待。针对远程场景我的经验是确认网络稳定后再连。如果是不稳定的公共网络建议先连到稳定的办公网或热点再打开远程项目。在 WSL 环境里注意把项目目录放在 Linux 文件系统内比如/home/user/project而不是放在/mnt/c跨盘访问。跨盘 IO 性能很差很容易造成等待。远程模式下可以调整文件监视器为轮询模式适当延长轮询间隔减少对网络 IO 的依赖。对共享网络盘NAS/SMB如果不需要实时同步可以在设置里把files.watcherExclude加上网络盘路径避免网络 IO 拖慢编辑器。远程通道的问题还有一个信号可以参考窗口左下角状态栏显示 SSH: hostname 或 WSL: Ubuntu 时如果等待发生在网络切换、休眠唤醒之后大概率是通道已经过期。这时直接在命令面板执行 Remote-SSH: Kill VS Code Server on Host 或 Reload Window强制重建连接通常能立刻恢复。4. 长期预防与性能优化配置问题解决了之后还要防止它再回来。我的习惯是把 VSCode 当成一个需要整理房间的环境看待哪些文件监视、哪些不监视哪些自动保存开、哪些关都是有讲究的。长期预防比一次排障更值钱。4.1 合理配置 settings.json 的关键参数下面这组配置是我在自己长期使用中沉淀下来的每个参数我都知道它解决什么问题你可以直接贴进settings.json按需调整{ files.autoSave: off, files.autoSaveDelay: 1000, files.watcherExclude: { **/.git/objects/**: true, **/.git/subtree-cache/**: true, **/node_modules/*/**: true, **/.next/**: true, **/dist/**: true, **/build/**: true, **/coverage/**: true }, files.exclude: { **/.git: true, **/.DS_Store: true, **/node_modules: true, **/dist: true }, search.useIgnoreFiles: true, search.exclude: { **/node_modules: true, **/bower_components: true, **/dist: true }, search.followSymlinks: false, editor.formatOnSave: false }第一个值得解释的是files.autoSave: off。很多人觉得自动保存很省事实际上在文件系统 IO 慢、扩展多、项目大的场景下自动保存会制造大量后台写盘任务。我见过一个极端例子用户开着自动保存一边输入一边格式化整个窗口卡了快 20 秒。改成手动保存CtrlS之后反而再没卡过。第二个是search.exclude单独列不要只依赖files.exclude。二者作用不同files.exclude是让资源管理器不显示这些目录search.exclude才是真正让搜索和文件扫描跳过它们。只改前者搜索时照样会扫 node_modules等于没优化。第三点是files.watcherExclude的颗粒度。**/node_modules/*/**这种写法比**/node_modules/**更精准但如果你的 node_modules 很庞大直接用后者更省心。判断标准是代码提示和 git 状态变化如果变慢就说明你排除过度了需要放宽。4.2 养成健康的文件操作习惯工具配置完了操作习惯也得跟上。以下几个习惯我能保证对减少等待有实际帮助不要同时打开几十个标签页还都保持未保存状态。每多一个未保存文件就等于多了一个热退出负担。大文件比如几十 MB 的日志不要在 VSCode 里直接打开。VSCode 不是文本巨物浏览器打开大文件会触发全文着色、标签折叠编辑器瞬间进入假死状态。这类文件用专门的工具或命令行查看工具处理更合适。定期重启 VSCode尤其在长时间挂机、切换网络、休眠唤醒后。别信编辑器不用重启的说法文件句柄和 watcher 资源是真会被耗尽。删除文件前先检查这个文件是否在某些扩展里被引用中。比如 ESLint、TypeScript Language Server 的缓存有时会因为引用失效而卡住删除流程。尽量不在资源管理器里右键做删除操作尤其是大型目录。我通常先选中文件再按 Delete 键或者直接在终端里rm指定路径删完再回到编辑器里确认两侧同步更稳。4.3 备选工具与边界认知最后说句实话VSCode 的文件系统抽象层设计思路很好但它不是万能的。如果某个项目常年卡在等待中、怎么都调不顺我建议你重新审视是不是工具和场景不匹配。有些场景更适合换工具超大日志分析用glogg、lnav这类流式阅读器。远程容器开发可以先sshfs挂载到本地再编辑。批量重命名或删除大量文件先写脚本在终端里处理处理完再回到 VSCode 刷新。只读目录、系统关键目录、大量符号链接的目录尽量别用 VSCode 直接管理它遇到权限和链接问题时的等待体验是灾难级的。认知边界摆正之后你不会再觉得是 VSCode 坏了而是知道这类场景本来就不该让编辑器硬扛。5. 常见问题速查表以下这些问题是社区里问得最勤、也是我自己和身边同事踩过最多的我把它们整理成一张速查表。遇到类似问题时直接对照排查能省不少时间。症状优先怀疑方向快速处理打开任何文件都显示加载中Hot Exit 残留 / File Watcher 耗尽清理备份目录配置 watcherExclude右键新建文件名字敲完不落盘目录被同步盘或杀软占用临时退出同步或杀软再试把目录加入白名单CtrlS 后状态栏无限转圈formatOnSave 或自动保存写盘冲突关闭 formatOnSave将文件保存到本地再测试右键删除文件提示被占用本地进程锁文件lsof/handle 定位占用进程杀掉后重试删除小文件都卡UI 死一半某个扩展事件回调未返回Disable All Extensions 后逐个启用WSL/远程模式下访问文件慢跨盘访问或通道过期把项目放到 Linux 文件系统Reload Window搜索 CtrlShiftF 转圈正在扫描 node_modules配置 search.exclude 和 useIgnoreFiles保存时页面冻结几秒大文件全量格式化关闭 formatOnSave不要用 VSCode 打开超大文件这张表解决的是 80% 的常见情况。如果你遇到的问题不在表内也没关系按上一节从简到繁的顺序一步步排查大概率能找到元凶。排查时记住一个原则改一步测一次改完不生效就回滚不要同时动多项配置不然你根本不知道是谁修好的。6. 写在最后我的一些实操体会这类一直等待中的问题我在多个环境里排查过说实话能一次性确诊的比例并不高通常都是先怀疑文件占用再看扩展最后发现是某个不起眼的目录没有排除。所以如果你折腾了半天没解决先别急着骂 VSCode 或重装只要按章法来绝大多数都能找到原因。我个人最受用的是备份目录清理 watcherExclude 排除 node_modules这两招几乎覆盖了我遇到的一半卡顿场景。另外一个小技巧遇到顽固卡死时敲CtrlShiftP输入 Developer: Reload Window很多时候只需要重载窗口就能恢复不用关掉整个软件。还有一点排查过程中千万不要把所有扩展一次性全禁用后就不管了一定要逐个启用、逐个验证否则即使恢复了你也不知道以后该躲哪个雷。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进