fix: stop note navigation from scaling with vault size
This commit is contained in:
106
src/utils/noteOpenPerformance.ts
Normal file
106
src/utils/noteOpenPerformance.ts
Normal file
@@ -0,0 +1,106 @@
|
||||
type NoteOpenStage =
|
||||
| 'beforeNavigateStart'
|
||||
| 'beforeNavigateEnd'
|
||||
| 'cacheReady'
|
||||
| 'contentLoadStart'
|
||||
| 'contentLoadEnd'
|
||||
| 'editorSwapped'
|
||||
|
||||
interface NoteOpenTrace {
|
||||
startedAt: number
|
||||
source: string
|
||||
marks: Partial<Record<NoteOpenStage, number>>
|
||||
}
|
||||
|
||||
const inFlightNoteOpens = new Map<string, NoteOpenTrace>()
|
||||
|
||||
function isVitestRuntime(): boolean {
|
||||
return typeof process !== 'undefined' && process.env.VITEST === 'true'
|
||||
}
|
||||
|
||||
function canMeasurePerformance(): boolean {
|
||||
return import.meta.env.DEV && typeof performance !== 'undefined' && !isVitestRuntime()
|
||||
}
|
||||
|
||||
function formatDuration(durationMs: number | null): string {
|
||||
return durationMs === null ? 'n/a' : `${durationMs.toFixed(1)}ms`
|
||||
}
|
||||
|
||||
function measureDuration(
|
||||
trace: NoteOpenTrace,
|
||||
start: keyof NoteOpenTrace['marks'] | 'startedAt',
|
||||
end: keyof NoteOpenTrace['marks'],
|
||||
): number | null {
|
||||
const startTime = start === 'startedAt' ? trace.startedAt : trace.marks[start]
|
||||
const endTime = trace.marks[end]
|
||||
if (startTime === undefined || endTime === undefined) return null
|
||||
return endTime - startTime
|
||||
}
|
||||
|
||||
function logPerf(message: string): void {
|
||||
if (!canMeasurePerformance()) return
|
||||
console.debug(`[perf] ${message}`)
|
||||
}
|
||||
|
||||
export function beginNoteOpenTrace(path: string, source: string): void {
|
||||
if (!canMeasurePerformance()) return
|
||||
|
||||
const startedAt = performance.now()
|
||||
for (const [otherPath, trace] of inFlightNoteOpens) {
|
||||
if (otherPath === path) continue
|
||||
logPerf(`noteOpen cancel path=${otherPath} source=${trace.source} total=${formatDuration(startedAt - trace.startedAt)} reason=superseded`)
|
||||
inFlightNoteOpens.delete(otherPath)
|
||||
}
|
||||
|
||||
inFlightNoteOpens.set(path, { startedAt, source, marks: {} })
|
||||
}
|
||||
|
||||
export function markNoteOpenTrace(path: string, stage: NoteOpenStage): void {
|
||||
if (!canMeasurePerformance()) return
|
||||
const trace = inFlightNoteOpens.get(path)
|
||||
if (!trace) return
|
||||
trace.marks[stage] = performance.now()
|
||||
}
|
||||
|
||||
export function finishNoteOpenTrace(path: string): void {
|
||||
if (!canMeasurePerformance()) return
|
||||
const trace = inFlightNoteOpens.get(path)
|
||||
if (!trace) return
|
||||
|
||||
trace.marks.editorSwapped = performance.now()
|
||||
const total = trace.marks.editorSwapped - trace.startedAt
|
||||
const beforeNavigate = measureDuration(trace, 'beforeNavigateStart', 'beforeNavigateEnd')
|
||||
const contentLoad = measureDuration(trace, 'contentLoadStart', 'contentLoadEnd')
|
||||
const editorSwap = measureDuration(trace, 'contentLoadEnd', 'editorSwapped')
|
||||
?? measureDuration(trace, 'beforeNavigateEnd', 'editorSwapped')
|
||||
?? measureDuration(trace, 'startedAt', 'editorSwapped')
|
||||
|
||||
logPerf(
|
||||
`noteOpen path=${path} source=${trace.source} total=${formatDuration(total)} `
|
||||
+ `beforeNavigate=${formatDuration(beforeNavigate)} `
|
||||
+ `contentLoad=${formatDuration(contentLoad)} `
|
||||
+ `editorSwap=${formatDuration(editorSwap)} `
|
||||
+ `cache=${trace.marks.cacheReady !== undefined ? 'hit' : 'miss'}`,
|
||||
)
|
||||
inFlightNoteOpens.delete(path)
|
||||
}
|
||||
|
||||
export function failNoteOpenTrace(path: string, reason: string): void {
|
||||
if (!canMeasurePerformance()) return
|
||||
const trace = inFlightNoteOpens.get(path)
|
||||
if (!trace) return
|
||||
|
||||
const total = performance.now() - trace.startedAt
|
||||
logPerf(`noteOpen cancel path=${path} source=${trace.source} total=${formatDuration(total)} reason=${reason}`)
|
||||
inFlightNoteOpens.delete(path)
|
||||
}
|
||||
|
||||
export function logKeyboardNavigationTrace(
|
||||
direction: 'up' | 'down',
|
||||
itemCount: number,
|
||||
durationMs: number,
|
||||
): void {
|
||||
if (!canMeasurePerformance()) return
|
||||
if (itemCount < 500 && durationMs < 4) return
|
||||
logPerf(`noteListKeyboard direction=${direction} items=${itemCount} move=${formatDuration(durationMs)}`)
|
||||
}
|
||||
Reference in New Issue
Block a user