跳到主要内容

扩展宿主单线程会卡住谁?

结论​

一个扩展宿主里的 JavaScript 是单线程事件循环。你在里面做同步重活或长时间不让出的循环,会卡住同一个宿主里的所有插件:命令不响应、补全不出来、树不刷新。不会直接把渲染进程的滚动全部写死,但用户会觉得编辑器功能失效。

展开​

扩展宿主和渲染进程是分开的。渲染进程负责画界面和编辑器输入。扩展宿主负责插件代码。宿主卡住时:

  • 这个宿主上的命令、事件、语言 Provider、树的 getChildren 都排在队列里
  • 已经发出去的 Webview 页面还能动,但消息要等宿主回来才处理
  • 另一个宿主不受影响。远程时本地 UI 宿主和远端工作区宿主是两个循环

会卡住的写法:

  • 大文件 readFileSync
  • 深递归扫描不加让步
  • 在 while 里同步解析整个仓库
  • activate 里 execSync

不会因为「写了 async」就自动不卡。async 函数里如果没有真正的 IO 等待,中间是一大段同步计算,事件循环同样出不去。

办法:

  • 计算放到语言服务器或 worker_threads,结果再交回宿主
  • 循环里分段,用 setTimeout 或调度让出
  • Provider 认取消令牌,过期就停
  • 文件一律异步,优先 workspace.fs

共享宿主是面试里的关键句:你的性能问题会变成别人插件的故障。

容易讲错的点​

  • 不是整个 Electron 只有一个线程。渲染、扩展宿主、语言服务器、调试适配器都可以是不同进程。
  • 卡的是你所在的那个宿主。把重活丢进 Webview 会改成卡住页面,不一定更好,只是换了线程。
  • Promise 并发不等于并行计算。CPU 密集仍会占满这一条 JavaScript 线程。