VS Code扩展如何判断TypeScript语言服务已就绪可查询?
如何等待VS Code中TypeScript语言服务就绪后发起请求?
我正在开发一款名为Any Xray的VS Code扩展,它会向内置TypeScript语言服务发送quickinfo请求,目标是查找类型为any的符号。目前使用的查询代码如下:
/** Leverages the `tsserver` protocol to try to get the type info at the given `position`. */ export async function quickInfoRequest(model: vscode.TextDocument, position: vscode.Position) { const { scheme, fsPath, authority, path } = model.uri; return await vscode.commands.executeCommand<QuickInfoResponse | undefined>( "typescript.tsserverRequest", "quickinfo", { file: scheme === 'file' ? fsPath : `^/${scheme}/${authority || 'ts-nul-authority'}/${path.replace(/^\//, '')}`, line: position.line + 1, offset: position.character, } satisfies FileLocationRequestArgs ); }
该方案运行良好,但前提是需在语言服务完全加载并“稳定”后再发起查询。如果过早发起涉及导入的查询,语言服务会返回any类型,导致大量误报警告。我希望等待TypeScript服务准备就绪后再发起请求,请问是否有办法检查服务是否仍在加载中?或者是否有可监听的事件来获知服务已就绪可查询?
解决方案
1. 监听typescript.tsServerStarted事件
VS Code的TypeScript扩展会在服务启动完成后触发typescript.tsServerStarted命令事件,你可以通过监听这个事件来标记服务就绪状态:
let tsServerReady = false; // 在扩展激活逻辑中注册监听 export function activate(context: vscode.ExtensionContext) { // 监听TS服务启动完成事件 const serverStartedDisposable = vscode.commands.registerCommand('typescript.tsServerStarted', () => { tsServerReady = true; serverStartedDisposable.dispose(); // 只需要监听一次启动 }); context.subscriptions.push(serverStartedDisposable); // 配置变更时重置就绪状态(可选) const configChangeDisposable = vscode.workspace.onDidChangeConfiguration(e => { if (e.affectsConfiguration('typescript')) { tsServerReady = false; // 重新监听服务启动 const newDisposable = vscode.commands.registerCommand('typescript.tsServerStarted', () => { tsServerReady = true; newDisposable.dispose(); }); context.subscriptions.push(newDisposable); } }); context.subscriptions.push(configChangeDisposable); } // 封装安全的查询函数 async function safeQuickInfoRequest(model: vscode.TextDocument, position: vscode.Position) { // 等待服务就绪 if (!tsServerReady) { await new Promise(resolve => { const disposable = vscode.commands.registerCommand('typescript.tsServerStarted', () => { tsServerReady = true; disposable.dispose(); resolve(null); }); }); } return quickInfoRequest(model, position); }
2. 通过projectInfo请求检查服务状态
你可以向TS服务发送projectInfo请求,根据返回结果判断服务是否能正常处理请求:
async function isTsServerReady(document: vscode.TextDocument): Promise<boolean> { try { const response = await vscode.commands.executeCommand( "typescript.tsserverRequest", "projectInfo", { file: document.uri.fsPath, needFileNameList: false } ); // 无错误且返回有效数据则认为就绪 return !!response && typeof response === 'object' && !response.error; } catch (error) { return false; } } // 带重试的安全查询 async function safeQuickInfoRequest(model: vscode.TextDocument, position: vscode.Position) { // 循环检查直到服务就绪,添加延迟避免频繁请求 while (!await isTsServerReady(model)) { await new Promise(resolve => setTimeout(resolve, 150)); } return quickInfoRequest(model, position); }
3. 结合文本编辑器状态监听
如果你的查询是在文件打开时触发,可以结合onDidOpenTextDocument事件,等待文档关联的TS服务完成初始化:
context.subscriptions.push( vscode.workspace.onDidOpenTextDocument(async doc => { if (doc.languageId === 'typescript' || doc.languageId === 'typescriptreact') { // 等待服务就绪 await safeQuickInfoRequest(doc, new vscode.Position(0, 0)); // 执行后续逻辑 } }) );
注意事项
- 大型项目中TS服务加载依赖的时间较长,建议结合延迟重试机制,避免一次性判断失败就终止流程
- 若扩展需要处理动态配置变更,记得在配置更新后重置服务就绪状态,确保后续查询的准确性
内容的提问来源于stack exchange,提问作者danvk
相关产品推荐
相关产品推荐

