From 878f4378cdee3c41f7643d9c7693bb607344d0c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=83=BD=E5=AE=81?= Date: Sun, 5 Nov 2023 14:59:19 +0800 Subject: [PATCH] perf: reduce duplicate rendering in localSearch (#3170) Co-authored-by: Divyansh Singh <40380293+brc-dd@users.noreply.github.com> --- .../components/VPLocalSearchBox.vue | 10 +++--- src/client/theme-default/support/lru.ts | 33 +++++++++++++++++++ 2 files changed, 39 insertions(+), 4 deletions(-) create mode 100644 src/client/theme-default/support/lru.ts diff --git a/src/client/theme-default/components/VPLocalSearchBox.vue b/src/client/theme-default/components/VPLocalSearchBox.vue index d9df6a0a..07b1bd15 100644 --- a/src/client/theme-default/components/VPLocalSearchBox.vue +++ b/src/client/theme-default/components/VPLocalSearchBox.vue @@ -31,6 +31,7 @@ import { import type { ModalTranslations } from '../../../../types/local-search' import { pathToFile } from '../../app/utils' import { useData } from '../composables/data' +import { LRUCache } from '../support/lru' import { createTranslate } from '../support/translation' const emit = defineEmits<{ @@ -142,6 +143,8 @@ const mark = computedAsync(async () => { return markRaw(new Mark(resultsEl.value)) }, null) +const cache = new LRUCache>(16) // 16 files + debouncedWatch( () => [searchIndex.value, filterText.value, showDetailedList.value] as const, async ([index, filterTextValue, showDetailedListValue], old, onCleanup) => { @@ -163,13 +166,12 @@ debouncedWatch( ? await Promise.all(results.value.map((r) => fetchExcerpt(r.id))) : [] if (canceled) return - const c = new Map>() for (const { id, mod } of mods) { const mapId = id.slice(0, id.indexOf('#')) - let map = c.get(mapId) + let map = cache.get(mapId) if (map) continue map = new Map() - c.set(mapId, map) + cache.set(mapId, map) const comp = mod.default ?? mod if (comp?.render || comp?.setup) { const app = createApp(comp) @@ -209,7 +211,7 @@ debouncedWatch( results.value = results.value.map((r) => { const [id, anchor] = r.id.split('#') - const map = c.get(id) + const map = cache.get(id) const text = map?.get(anchor) ?? '' for (const term in r.match) { terms.add(term) diff --git a/src/client/theme-default/support/lru.ts b/src/client/theme-default/support/lru.ts new file mode 100644 index 00000000..bad3f2b4 --- /dev/null +++ b/src/client/theme-default/support/lru.ts @@ -0,0 +1,33 @@ +// adapted from https://stackoverflow.com/a/46432113/11613622 + +export class LRUCache { + private max: number + private cache: Map + + constructor(max: number = 10) { + this.max = max + this.cache = new Map() + } + + get(key: K): V | undefined { + let item = this.cache.get(key) + if (item !== undefined) { + // refresh key + this.cache.delete(key) + this.cache.set(key, item) + } + return item + } + + set(key: K, val: V): void { + // refresh key + if (this.cache.has(key)) this.cache.delete(key) + // evict oldest + else if (this.cache.size === this.max) this.cache.delete(this.first()!) + this.cache.set(key, val) + } + + first(): K | undefined { + return this.cache.keys().next().value + } +}