From 8cb0785582f1c9f18f2c5a0852a17bae9e29a4e8 Mon Sep 17 00:00:00 2001 From: lin onetwo Date: Thu, 23 May 2024 01:57:42 +0800 Subject: [PATCH] feat: debounce to save CPU --- src/commandpalette/configs/config.tid | 4 ++- src/commandpalette/configs/configs.multids | 3 +- .../language/en-GB/Translations.multids | 2 ++ .../language/zh-Hans/Translations.multids | 2 ++ .../command-action-string.ts | 7 +++-- .../build-in-sub-plugins/command-message.ts | 7 +++-- .../build-in-sub-plugins/search-config.ts | 7 +++-- .../build-in-sub-plugins/search-filter.ts | 9 +++--- .../search-system-title.ts | 7 +++-- .../build-in-sub-plugins/search-tags.ts | 7 +++-- .../build-in-sub-plugins/search-user-text.ts | 7 +++-- .../search-user-title-pinyin.ts | 7 +++-- .../build-in-sub-plugins/search-user-title.ts | 7 +++-- src/commandpalette/widgets/utils/debounce.ts | 28 +++++++++++++++++++ 14 files changed, 74 insertions(+), 30 deletions(-) create mode 100644 src/commandpalette/widgets/utils/debounce.ts diff --git a/src/commandpalette/configs/config.tid b/src/commandpalette/configs/config.tid index 507f915..4d4c404 100644 --- a/src/commandpalette/configs/config.tid +++ b/src/commandpalette/configs/config.tid @@ -19,4 +19,6 @@ caption: <> ;<> :<$edit-text tiddler="$:/plugins/linonetwo/commandpalette/configs/TextAlias" tabindex=-1 focus=false cancelPopups="yes" fileDrop=no tag="input" /> <> ;<> -:<$edit-text tiddler="$:/plugins/linonetwo/commandpalette/configs/DesktopWidth" tabindex=-1 focus=false cancelPopups="yes" fileDrop=no tag="input" type="number" />% <> \ No newline at end of file +:<$edit-text tiddler="$:/plugins/linonetwo/commandpalette/configs/DesktopWidth" tabindex=-1 focus=false cancelPopups="yes" fileDrop=no tag="input" type="number" />% <> +;<> +:<$edit-text tiddler="$:/plugins/linonetwo/commandpalette/configs/DebounceDuration" tabindex=-1 focus=false cancelPopups="yes" fileDrop=no tag="input" type="number" />ms <> \ No newline at end of file diff --git a/src/commandpalette/configs/configs.multids b/src/commandpalette/configs/configs.multids index ef450e0..d3c7616 100644 --- a/src/commandpalette/configs/configs.multids +++ b/src/commandpalette/configs/configs.multids @@ -4,4 +4,5 @@ TitleAlias: title caption alias TextAlias: text keywords HideDefaultSearchBar: no TitlePriorityText: no -DesktopWidth: 80 \ No newline at end of file +DesktopWidth: 80 +DebounceDuration: 300 \ No newline at end of file diff --git a/src/commandpalette/language/en-GB/Translations.multids b/src/commandpalette/language/en-GB/Translations.multids index 938fc2d..ef61e21 100644 --- a/src/commandpalette/language/en-GB/Translations.multids +++ b/src/commandpalette/language/en-GB/Translations.multids @@ -14,6 +14,8 @@ Configs/DesktopWidth/Caption: Width on desktop mode Configs/DesktopWidth/Description: Width of the input and result boxes on the screen (does not affect mobile, which is full screen by default) Configs/TitlePriorityText/Caption: Title higher than text. Configs/TitlePriorityText/Description: When checked, title search results will be listed on the top, and text search results will be listed below, when searching user tiddlers. (The result on the bottom can be selected by pressing the ↑ up arrow key to circle go to the bottom of the search results) +Configs/DebounceDuration/Caption: Search debounce duration +Configs/DebounceDuration/Description: Pressing a key to search once will lead to lagging, here set the search anti-shake duration, meaning two consecutive key presses within this duration will be judged as inputting, and will wait for you to finish typing before searching, in milliseconds. SystemTitle: Title of system tiddler UserTitle: Title of user tiddler UserTitlePinyin: Title Pinyin of user tiddler diff --git a/src/commandpalette/language/zh-Hans/Translations.multids b/src/commandpalette/language/zh-Hans/Translations.multids index 6c15617..4ac9710 100644 --- a/src/commandpalette/language/zh-Hans/Translations.multids +++ b/src/commandpalette/language/zh-Hans/Translations.multids @@ -14,6 +14,8 @@ Configs/DesktopWidth/Caption: 桌面模式宽度 Configs/DesktopWidth/Description: 输入框和结果框占屏幕的宽度(不影响移动端,移动端默认全屏) Configs/TitlePriorityText/Caption: 标题高于内容 Configs/TitlePriorityText/Description: 勾选后,在搜索用户内容时,将标题搜索结果排在上面,内容搜索结果排在下面。(下面的内容可以通过按↑上方向键转到搜索结果的底部来选择) +Configs/DebounceDuration/Caption: 搜索防抖时长 +Configs/DebounceDuration/Description: 按一个键就搜一次会导致卡顿,这里设置搜索防抖时长,意思是两次连续按键在这个时长内就判定为输入中,就会等你输入完再搜索,单位毫秒。 UserTitle: 用户条目标题 SystemTitle: 系统条目标题 UserTitlePinyin: 用户条目标题拼音 diff --git a/src/commandpalette/widgets/build-in-sub-plugins/command-action-string.ts b/src/commandpalette/widgets/build-in-sub-plugins/command-action-string.ts index 24f6846..cb0a931 100644 --- a/src/commandpalette/widgets/build-in-sub-plugins/command-action-string.ts +++ b/src/commandpalette/widgets/build-in-sub-plugins/command-action-string.ts @@ -4,18 +4,19 @@ import type { AutocompletePlugin } from '@algolia/autocomplete-js'; import { ITiddlerFields } from 'tiddlywiki'; import { checkIsSearchSystem, checkIsUnderFilter } from '../utils/checkPrefix'; import { IContext } from '../utils/context'; +import { debounced } from '../utils/debounce'; import { filterTiddlersAsync } from '../utils/filterTiddlersAsync'; import { lingo } from '../utils/lingo'; import { renderTextWithCache } from '../utils/renderTextWithCache'; export const plugin = { - getSources(parameters) { + async getSources(parameters) { if (parameters.query.length === 0) return []; if (!checkIsSearchSystem(parameters) || checkIsUnderFilter(parameters)) return []; const focusedTiddler = $tw.wiki.getTiddlerText('$:/temp/focussedTiddler'); const variables = { currentTiddler: focusedTiddler ?? '', commandpaletteinput: parameters.query.slice(1) }; const { widget } = parameters.state.context as IContext; - return [ + return await debounced([ { sourceId: 'actionString', async getItems({ query }) { @@ -60,6 +61,6 @@ export const plugin = { }, }, }, - ]; + ]); }, } satisfies AutocompletePlugin; diff --git a/src/commandpalette/widgets/build-in-sub-plugins/command-message.ts b/src/commandpalette/widgets/build-in-sub-plugins/command-message.ts index 6107231..8c3b7f3 100644 --- a/src/commandpalette/widgets/build-in-sub-plugins/command-message.ts +++ b/src/commandpalette/widgets/build-in-sub-plugins/command-message.ts @@ -3,18 +3,19 @@ import type { AutocompletePlugin } from '@algolia/autocomplete-js'; import { ITiddlerFields } from 'tiddlywiki'; import { checkIsSearchSystem, checkIsUnderFilter } from '../utils/checkPrefix'; import { IContext } from '../utils/context'; +import { debounced } from '../utils/debounce'; import { filterTiddlersAsync } from '../utils/filterTiddlersAsync'; import { lingo } from '../utils/lingo'; import { renderTextWithCache } from '../utils/renderTextWithCache'; export const plugin = { - getSources(parameters) { + async getSources(parameters) { if (parameters.query.length === 0) return []; if (!checkIsSearchSystem(parameters) || checkIsUnderFilter(parameters)) return []; const focusedTiddler = $tw.wiki.getTiddlerText('$:/temp/focussedTiddler'); const variables = { currentTiddler: focusedTiddler ?? '' }; const { widget } = parameters.state.context as IContext; - return [ + return await debounced([ { sourceId: 'message', async getItems({ query }) { @@ -70,6 +71,6 @@ export const plugin = { }, }, }, - ]; + ]); }, } satisfies AutocompletePlugin; diff --git a/src/commandpalette/widgets/build-in-sub-plugins/search-config.ts b/src/commandpalette/widgets/build-in-sub-plugins/search-config.ts index 9a353cd..ce86dcc 100644 --- a/src/commandpalette/widgets/build-in-sub-plugins/search-config.ts +++ b/src/commandpalette/widgets/build-in-sub-plugins/search-config.ts @@ -3,16 +3,17 @@ import type { AutocompletePlugin } from '@algolia/autocomplete-js'; import { ITiddlerFields } from 'tiddlywiki'; import { checkIsSearchSystem, checkIsUnderFilter } from '../utils/checkPrefix'; import { IContext } from '../utils/context'; +import { debounced } from '../utils/debounce'; import { filterTiddlersAsync } from '../utils/filterTiddlersAsync'; import { lingo } from '../utils/lingo'; import { renderTextWithCache } from '../utils/renderTextWithCache'; export const plugin = { - getSources(parameters) { + async getSources(parameters) { if (parameters.query.length === 0) return []; if (!checkIsSearchSystem(parameters) || checkIsUnderFilter(parameters)) return []; const { widget } = parameters.state.context as IContext; - return [ + return await debounced([ { sourceId: 'config', async getItems({ query }) { @@ -42,6 +43,6 @@ export const plugin = { }, }, }, - ]; + ]); }, } satisfies AutocompletePlugin; diff --git a/src/commandpalette/widgets/build-in-sub-plugins/search-filter.ts b/src/commandpalette/widgets/build-in-sub-plugins/search-filter.ts index 7edd0ec..e76aa6d 100644 --- a/src/commandpalette/widgets/build-in-sub-plugins/search-filter.ts +++ b/src/commandpalette/widgets/build-in-sub-plugins/search-filter.ts @@ -1,15 +1,16 @@ /* eslint-disable @typescript-eslint/strict-boolean-expressions */ -import type { AutocompletePlugin, GetSources } from '@algolia/autocomplete-js'; +import type { AutocompletePlugin, AutocompleteSource } from '@algolia/autocomplete-js'; import { ITiddlerFields } from 'tiddlywiki'; import { checkIsFilter, checkIsSearchSystem, checkIsUnderFilter } from '../utils/checkPrefix'; import { IContext } from '../utils/context'; +import { debounced } from '../utils/debounce'; import { filterTiddlersAsync } from '../utils/filterTiddlersAsync'; import { lingo } from '../utils/lingo'; import { renderTextWithCache } from '../utils/renderTextWithCache'; export const plugin = { - getSources(parameters) { - const sources: ReturnType> = []; + async getSources(parameters) { + const sources: Array> = []; if (checkIsFilter(parameters)) { const { widget } = parameters.state.context as IContext; sources.push({ @@ -96,6 +97,6 @@ export const plugin = { }, }); } - return sources; + return await debounced(sources); }, } satisfies AutocompletePlugin; diff --git a/src/commandpalette/widgets/build-in-sub-plugins/search-system-title.ts b/src/commandpalette/widgets/build-in-sub-plugins/search-system-title.ts index 35c59bc..95a5f61 100644 --- a/src/commandpalette/widgets/build-in-sub-plugins/search-system-title.ts +++ b/src/commandpalette/widgets/build-in-sub-plugins/search-system-title.ts @@ -1,14 +1,15 @@ import type { AutocompletePlugin } from '@algolia/autocomplete-js'; import { ITiddlerFields } from 'tiddlywiki'; import { checkIsSearchSystem, checkIsUnderFilter } from '../utils/checkPrefix'; +import { debounced } from '../utils/debounce'; import { filterTiddlersAsync } from '../utils/filterTiddlersAsync'; import { lingo } from '../utils/lingo'; export const plugin = { - getSources(parameters) { + async getSources(parameters) { if (parameters.query.length === 0) return []; if (!checkIsSearchSystem(parameters) || checkIsUnderFilter(parameters)) return []; - return [ + return await debounced([ { sourceId: 'system-title', async getItems({ query }) { @@ -30,6 +31,6 @@ export const plugin = { }, }, }, - ]; + ]); }, } satisfies AutocompletePlugin; diff --git a/src/commandpalette/widgets/build-in-sub-plugins/search-tags.ts b/src/commandpalette/widgets/build-in-sub-plugins/search-tags.ts index 82e9365..b6d2a7e 100644 --- a/src/commandpalette/widgets/build-in-sub-plugins/search-tags.ts +++ b/src/commandpalette/widgets/build-in-sub-plugins/search-tags.ts @@ -2,16 +2,17 @@ import type { AutocompletePlugin } from '@algolia/autocomplete-js'; import { ITiddlerFields } from 'tiddlywiki'; import { checkIsSearchTags } from '../utils/checkPrefix'; import { IContext } from '../utils/context'; +import { debounced } from '../utils/debounce'; import { filterTiddlersAsync } from '../utils/filterTiddlersAsync'; import { lingo } from '../utils/lingo'; export const plugin = { - getSources(parameters) { + async getSources(parameters) { if (parameters.query.length === 0) return []; if (!checkIsSearchTags(parameters)) { return []; } - return [{ + return await debounced([{ // suggest tags for user to search sourceId: 'tags', async getItems({ query }) { @@ -39,6 +40,6 @@ export const plugin = { return lingo('NoResult'); }, }, - }]; + }]); }, } satisfies AutocompletePlugin; diff --git a/src/commandpalette/widgets/build-in-sub-plugins/search-user-text.ts b/src/commandpalette/widgets/build-in-sub-plugins/search-user-text.ts index 7e9e07c..98b82eb 100644 --- a/src/commandpalette/widgets/build-in-sub-plugins/search-user-text.ts +++ b/src/commandpalette/widgets/build-in-sub-plugins/search-user-text.ts @@ -1,15 +1,16 @@ import type { AutocompletePlugin } from '@algolia/autocomplete-js'; import { ITiddlerFields } from 'tiddlywiki'; import { checkIsSearchUser, checkIsUnderFilter } from '../utils/checkPrefix'; +import { debounced } from '../utils/debounce'; import { filterTiddlersAsync } from '../utils/filterTiddlersAsync'; import { getFieldsAsText } from '../utils/getFieldsAsTitle'; import { lingo } from '../utils/lingo'; export const plugin = { - getSources(parameters) { + async getSources(parameters) { if (parameters.query.length === 0) return []; if (!checkIsSearchUser(parameters) || checkIsUnderFilter(parameters)) return []; - return [ + return await debounced([ { sourceId: 'text', async getItems({ query }) { @@ -56,6 +57,6 @@ export const plugin = { }, }, }, - ]; + ]); }, } satisfies AutocompletePlugin; diff --git a/src/commandpalette/widgets/build-in-sub-plugins/search-user-title-pinyin.ts b/src/commandpalette/widgets/build-in-sub-plugins/search-user-title-pinyin.ts index 637deaf..4aafca4 100644 --- a/src/commandpalette/widgets/build-in-sub-plugins/search-user-title-pinyin.ts +++ b/src/commandpalette/widgets/build-in-sub-plugins/search-user-title-pinyin.ts @@ -1,12 +1,13 @@ import type { AutocompletePlugin } from '@algolia/autocomplete-js'; import { ITiddlerFields } from 'tiddlywiki'; import { checkIsSearchUser, checkIsUnderFilter } from '../utils/checkPrefix'; +import { debounced } from '../utils/debounce'; import { filterTiddlersAsync } from '../utils/filterTiddlersAsync'; import { getFieldsAsTitle } from '../utils/getFieldsAsTitle'; import { lingo } from '../utils/lingo'; export const plugin = { - getSources(parameters) { + async getSources(parameters) { if (!checkIsSearchUser(parameters) || checkIsUnderFilter(parameters)) return []; if ( // check `pinyinfuse` operator is installed @@ -17,7 +18,7 @@ export const plugin = { return []; } if (parameters.query.length === 0) return []; - return [ + return await debounced([ { sourceId: 'title-pinyin', async getItems({ query }) { @@ -39,6 +40,6 @@ export const plugin = { }, }, }, - ]; + ]); }, } satisfies AutocompletePlugin; diff --git a/src/commandpalette/widgets/build-in-sub-plugins/search-user-title.ts b/src/commandpalette/widgets/build-in-sub-plugins/search-user-title.ts index 0d0d046..205e868 100644 --- a/src/commandpalette/widgets/build-in-sub-plugins/search-user-title.ts +++ b/src/commandpalette/widgets/build-in-sub-plugins/search-user-title.ts @@ -1,15 +1,16 @@ import type { AutocompletePlugin } from '@algolia/autocomplete-js'; import { ITiddlerFields } from 'tiddlywiki'; import { checkIsSearchUser, checkIsUnderFilter } from '../utils/checkPrefix'; +import { debounced } from '../utils/debounce'; import { filterTiddlersAsync } from '../utils/filterTiddlersAsync'; import { getFieldsAsTitle } from '../utils/getFieldsAsTitle'; import { lingo } from '../utils/lingo'; export const plugin = { - getSources(parameters) { + async getSources(parameters) { if (parameters.query.length === 0) return []; if (!checkIsSearchUser(parameters) || checkIsUnderFilter(parameters)) return []; - return [ + return await debounced([ { sourceId: 'title', async getItems({ query }) { @@ -31,6 +32,6 @@ export const plugin = { }, }, }, - ]; + ]); }, } satisfies AutocompletePlugin; diff --git a/src/commandpalette/widgets/utils/debounce.ts b/src/commandpalette/widgets/utils/debounce.ts new file mode 100644 index 0000000..d179bcb --- /dev/null +++ b/src/commandpalette/widgets/utils/debounce.ts @@ -0,0 +1,28 @@ +/* eslint-disable @typescript-eslint/strict-boolean-expressions */ +/* eslint-disable @typescript-eslint/no-explicit-any */ +/* eslint-disable @typescript-eslint/no-unsafe-return */ + +import { AutocompleteSource } from '@algolia/autocomplete-shared'; +import { ITiddlerFields } from 'tiddlywiki'; + +/* eslint-disable @typescript-eslint/no-unsafe-argument */ +type AnyFunction = (...arguments_: any[]) => any; + +export function debouncePromise(function_: T, time: number): (...arguments_: Parameters) => Promise> { + let timerId: ReturnType; + + return async function debounced(...arguments_: Parameters): Promise> { + if (timerId) { + clearTimeout(timerId); + } + + return await new Promise>((resolve) => { + timerId = setTimeout(() => { + resolve(function_(...arguments_)); + }, time); + }); + }; +} + +const debounceDuration = Number($tw.wiki.getTiddlerText('$:/plugins/linonetwo/commandpalette/configs/DebounceDuration', '300')); +export const debounced = debouncePromise(async (items: Array>) => await Promise.resolve(items), debounceDuration);