扩展宿主单线程会卡住谁?
结论
一个扩展宿主里的 JavaScript 是单线程事件循环。你在里面做同步重活或长时间不让出的循环,会卡住同一个宿主里的所有插件:命令不响应、补全不出来、树不刷新。不会直接把渲染进程的滚动全部写死,但用户会觉得编辑器功能失效。
展开
扩展宿主和渲染进程是分开的。渲染进程负责画界面和编辑器输入。扩展宿主负责插件代码。宿主卡住时:
- 这个宿主上的命令、事件、语言 Provider、树的
getChildren都排在队列里 - 已经发出去的 Webview 页面还能动,但消息要等宿主回来才处理
- 另一个宿主不受影响。远程时本地 UI 宿主和远端工作区宿主是两个循环
会卡住的写法:
- 大文件
readFileSync - 深递归扫描不加让步
- 在
while里同步解析整个仓库 activate里execSync
不会因为「写了 async」就自动不卡。async 函数里如果没有真正的 IO 等待,中间是一大段同步计算,事件循环同样出不去。
办法:
- 计算放到语言服务器或
worker_threads,结果再交回宿主 - 循环里分段,用
setTimeout或调度让出 - Provider 认取消令牌,过期就停
- 文件一律异步,优先
workspace.fs
共享宿主是面试里的关键句:你的性能问题会变成别人插件的故障。
容易讲错的点
- 不是整个 Electron 只有一个线程。渲染、扩展宿主、语言服务器、调试适配器都可以是不同进程。
- 卡的是你所在的那个宿主。把重活丢进 Webview 会改成卡住页面,不一定更好,只是换了线程。
- Promise 并发不等于并行计算。CPU 密集仍会占满这一条 JavaScript 线程。