取消令牌用来干什么?
结论
取消令牌表示「这个请求已经过时,别再算了」。用户连续打字时,旧的补全、悬停、诊断计算要能停下来,把 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。你要自己接上。 - 捕获取消异常后继续返回旧结果,界面会把过期补全插到新文本里。
- 不要用一个全局令牌取消所有功能。补全被取消不应该把正在进行的保存或重命名也取消掉。