⚡ perf(vscode): 预览发文档后在后台问语言扩展的请求排队发:同时在途最多 4 个、离视口近的先问、文档改了排着的作废,看得见的中文名先交

This commit is contained in:
cruldra committed 2026-10-13 14:15:37 +11:00
1 parent 5a0c5490ea
commit 12ad047b4d
7 files changed
+335 -45

No files matched your search

+30 -12
View File
@@ -46,7 +46,7 @@ describe('调用树棵数在文档发出去之后算', () => {
},
}
const posted: { type: string, counts?: Record<string, number> }[] = []
const session = new CallTreeSession(message => posted.push(message), () => source)
const session = new CallTreeSession(message => posted.push(message), () => source, () => 0)
session.documentSent()
await viFlush()
expect(posted).toEqual([{ type: 'callTreeCounts', version: 3, counts: { fn: 1, inner: 1 } }])
@@ -71,7 +71,7 @@ describe('调用树棵数在文档发出去之后算', () => {
},
}
const posted: unknown[] = []
const session = new CallTreeSession(message => posted.push(message), () => source)
const session = new CallTreeSession(message => posted.push(message), () => source, () => 0)
session.documentSent()
version = 2
session.documentSent()
@@ -91,7 +91,7 @@ describe('调用树棵数在文档发出去之后算', () => {
load: async () => ({ symbol: mask, edges: [edge] }),
}
const posted: { type: string, version?: number, anchor?: string, trees?: { name: string }[] }[] = []
const session = new CallTreeSession(message => posted.push(message), () => source)
const session = new CallTreeSession(message => posted.push(message), () => source, () => 0)
session.open(3, 'fn')
expect(posted).toEqual([])
session.documentSent()
@@ -124,7 +124,7 @@ describe('调用树棵数在文档发出去之后算', () => {
},
}
const posted: unknown[] = []
const session = new CallTreeSession(message => posted.push(message), () => source)
const session = new CallTreeSession(message => posted.push(message), () => source, () => 0)
session.documentSent()
await viFlush()
expect(posted).toEqual([{ type: 'callTreeCounts', version: 5, counts: {} }])
@@ -158,7 +158,7 @@ describe('调用树棵数在文档发出去之后算', () => {
load: async () => ({ symbol: symbol('nobody'), edges: [] }),
}
const posted: unknown[] = []
const session = new CallTreeSession(message => posted.push(message), () => source)
const session = new CallTreeSession(message => posted.push(message), () => source, () => 0)
session.documentSent()
await viFlush()
posted.length = 0
@@ -187,7 +187,7 @@ describe('调用树棵数在文档发出去之后算', () => {
},
}
const posted: unknown[] = []
const session = new CallTreeSession(message => posted.push(message), () => source)
const session = new CallTreeSession(message => posted.push(message), () => source, () => 0)
session.documentSent()
session.open(7, 'fn')
version = 8
@@ -210,7 +210,7 @@ describe('调用树棵数在文档发出去之后算', () => {
},
}
const posted: unknown[] = []
const session = new CallTreeSession(message => posted.push(message), () => source)
const session = new CallTreeSession(message => posted.push(message), () => source, () => 0)
session.documentSent()
await viFlush()
expect(asked).toEqual([endpoint])
@@ -231,7 +231,7 @@ describe('调用树棵数在文档发出去之后算', () => {
load: async () => ({ symbol: route, edges: callers, contractMiss: { files: ['web/src/lib/api/schema.d.ts'] } }),
}
const posted: unknown[] = []
const session = new CallTreeSession(message => posted.push(message), () => source)
const session = new CallTreeSession(message => posted.push(message), () => source, () => 0)
session.documentSent()
await viFlush()
expect(posted).toEqual([{ type: 'callTreeCounts', version: 10, counts: {} }])
@@ -277,7 +277,7 @@ describe('同一版文档又发一遍(页面重新加载、按新规则重发
},
}
const posted: unknown[] = []
const session = new CallTreeSession(message => posted.push(message), () => source)
const session = new CallTreeSession(message => posted.push(message), () => source, () => 0)
session.documentSent()
await viFlush()
expect(asked).toEqual(['fn', 'alone', 'unknown'])
@@ -314,7 +314,7 @@ describe('同一版文档又发一遍(页面重新加载、按新规则重发
},
}
const posted: unknown[] = []
const session = new CallTreeSession(message => posted.push(message), () => source)
const session = new CallTreeSession(message => posted.push(message), () => source, () => 0)
session.documentSent()
await viFlush()
expect(posted).toEqual([])
@@ -346,7 +346,7 @@ describe('同一版文档又发一遍(页面重新加载、按新规则重发
},
}
const posted: unknown[] = []
const session = new CallTreeSession(message => posted.push(message), () => source)
const session = new CallTreeSession(message => posted.push(message), () => source, () => 0)
session.documentSent()
await viFlush()
posted.length = 0
@@ -372,7 +372,7 @@ describe('同一版文档又发一遍(页面重新加载、按新规则重发
},
}
const posted: unknown[] = []
const session = new CallTreeSession(message => posted.push(message), () => source)
const session = new CallTreeSession(message => posted.push(message), () => source, () => 0)
session.documentSent()
await viFlush()
source.blocks = [route('/api/v1/agents'), block('fn', 'function', 1)]
@@ -388,6 +388,24 @@ describe('同一版文档又发一遍(页面重新加载、按新规则重发
})
})
describe('后台数的顺序', () => {
it('离视口近的块先问', async () => {
const asked: number[] = []
const source: CallTreeSource = {
version: 1,
blocks: [block('a', 'function', 10), block('b', 'function', 500), block('c', 'class', 300)],
load: async ({ defines }) => {
asked.push(defines?.startIndex ?? -1)
return { symbol: symbol('nobody'), edges: [] }
},
}
const session = new CallTreeSession(() => {}, () => source, offset => Math.abs(offset - 320))
session.documentSent()
await viFlush()
expect(asked).toEqual([300, 500, 10])
})
})
async function viFlush(): Promise<void> {
await new Promise(resolve => setTimeout(resolve, 0))
await new Promise(resolve => setTimeout(resolve, 0))
+21 -5
View File
@@ -58,6 +58,8 @@ export class CallTreeSession {
constructor(
private readonly post: (message: ExtensionToWebview) => void,
private readonly source: () => CallTreeSource | undefined,
/** 名字起点在 offset 的块离页面视口多远:后台先数近的 */
private readonly distance: (offset: number) => number,
) {}
/** 文档发出去了:还是手上这一版就接着用,换了一版就从头数。 */
@@ -104,7 +106,10 @@ export class CallTreeSession {
void this.scan(version)
}
/** 一块一块问还没问过的,每问完一块按眼下发出去的块树再找下一块(数的时候文档可能又按同一版重发了);问了才在数完时发棵数。 */
/**
* 一块一块问还没问过的,先问离视口近的;每问完一块按眼下发出去的块树、眼下的视口再挑下一块(数的时候文档可能又按同一版重发了、页面可能滚了)。
* 问了才在数完时发棵数。
*/
private async scan(version: number): Promise<void> {
this.scanning = version
let asked = false
@@ -113,7 +118,11 @@ export class CallTreeSession {
const src = this.source()
if (!src || this.stale(version))
return
const next = callBlocks(src.blocks).find(block => !this.answerOf(block))
let next: NamedCallBlock | undefined
for (const block of callBlocks(src.blocks)) {
if (!this.answerOf(block) && (!next || this.distance(block.defines.startIndex) < this.distance(next.defines.startIndex)))
next = block
}
if (!next)
break
asked = true
@@ -199,11 +208,11 @@ export class CallTreeSession {
}
/** 宿主标了能看调用树(callTree)、有名字起点的块,含嵌在别的块里面的。 */
function callBlocks(blocks: readonly CallTreeBlock[]): CallTreeBlock[] {
const found: CallTreeBlock[] = []
function callBlocks(blocks: readonly CallTreeBlock[]): NamedCallBlock[] {
const found: NamedCallBlock[] = []
const walk = (list: readonly CallTreeBlock[]) => {
for (const block of list) {
if (block.callTree && block.defines)
if (isNamedCallBlock(block))
found.push(block)
if (block.children?.length)
walk(block.children)
@@ -213,6 +222,13 @@ function callBlocks(blocks: readonly CallTreeBlock[]): CallTreeBlock[] {
return found
}
/** 能看调用树、有名字起点的块。 */
type NamedCallBlock = CallTreeBlock & Required<Pick<CallTreeBlock, 'defines'>>
function isNamedCallBlock(block: CallTreeBlock): block is NamedCallBlock {
return !!block.callTree && !!block.defines
}
/** 一块怎么问:名字起点和接口。同一版文档按新规则重发时接口可能变了(查到了挂载前缀),变了就得重问。 */
function targetOf(block: CallTreeBlock): string {
return JSON.stringify([block.defines?.startIndex, block.callTree?.endpoint])