跳到主要内容

取消令牌用来干什么?

结论​

取消令牌表示「这个请求已经过时,别再算了」。用户连续打字时,旧的补全、悬停、诊断计算要能停下来,把 CPU 让给最新一次。

展开​

VS Code 的 Provider 回调都会收到 CancellationToken:

provideCompletionItems(document, position, token) {
if (token.isCancellationRequested) {
return;
}
return compute(document, position, token);
}

语言服务器协议里,客户端发 $/cancelRequest,带上要取消的请求 id。服务器收到后应结束对应计算,并让原请求以取消结束,而不是再返回一份补全。

实践要点:

  • 长时间循环里检查 token.isCancellationRequested,或者把令牌传给底层 TypeScript 服务、网络请求的 AbortSignal。
  • 只在入口看一次不够。真正耗时的是后面的循环和 IO。
  • 取消不是失败。不要弹错误通知,也不要写日志的 error 级别。
  • 返回前再看一次文档 version。没取消但版本已经变了,同样丢掉。

诊断如果是推模型,没有天然的请求 id,就要自己做「只发布最新版本」。可以做成代数:每次变更加一,异步函数结束时代数不一致就 return。

容易讲错的点​

  • 令牌取消不会自动杀掉你起的子进程或 fetch。你要自己接上。
  • 捕获取消异常后继续返回旧结果,界面会把过期补全插到新文本里。
  • 不要用一个全局令牌取消所有功能。补全被取消不应该把正在进行的保存或重命名也取消掉。