From ba9dad95b4e7af65f8facf4184a9eeb9fa4e8736 Mon Sep 17 00:00:00 2001 From: EYHN Date: Wed, 27 Mar 2024 14:01:54 +0000 Subject: [PATCH] fix(core): improve performance (#6345) --- .../common/infra/src/livedata/livedata.ts | 30 +++++++++--- packages/common/infra/src/page/record.ts | 14 +++--- .../page-list/group-definitions.tsx | 47 +++++++++++-------- .../hooks/affine/use-doc-engine-status.tsx | 5 +- .../entities/tabs/journal.tsx | 8 ++-- .../core/src/pages/workspace/index.tsx | 2 +- 6 files changed, 66 insertions(+), 40 deletions(-) diff --git a/packages/common/infra/src/livedata/livedata.ts b/packages/common/infra/src/livedata/livedata.ts index 5a6539d96a..cb3cd819af 100644 --- a/packages/common/infra/src/livedata/livedata.ts +++ b/packages/common/infra/src/livedata/livedata.ts @@ -5,20 +5,22 @@ import type { OperatorFunction, Subscription, TeardownLogic, + ThrottleConfig, } from 'rxjs'; import { BehaviorSubject, combineLatest, distinctUntilChanged, EMPTY, - filter, map, + mergeMap, Observable, of, scan, skip, Subject, switchMap, + throttleTime, } from 'rxjs'; const logger = new DebugLogger('livedata'); @@ -97,11 +99,10 @@ export class LiveData ? upstream$ : stream$ => stream$.pipe( - filter( - (op): op is Exclude => op !== 'set' - ), - switchMap(v => { - if (v === 'get') { + mergeMap(v => { + if (v === 'set') { + return EMPTY; + } else if (v === 'get') { return of('watch' as const, 'unwatch' as const); } else { return of(v); @@ -333,6 +334,23 @@ export class LiveData return sub$; } + distinctUntilChanged(comparator?: (previous: T, current: T) => boolean) { + return LiveData.from( + this.pipe(distinctUntilChanged(comparator)), + null as any + ); + } + + throttleTime( + duration: number, + { trailing = true, leading = true }: ThrottleConfig = {} + ) { + return LiveData.from( + this.pipe(throttleTime(duration, undefined, { trailing, leading })), + null as any + ); + } + // eslint-disable-next-line rxjs/finnish asObservable(): Observable { return new Observable(subscriber => { diff --git a/packages/common/infra/src/page/record.ts b/packages/common/infra/src/page/record.ts index faf7f3bda6..cea2522b41 100644 --- a/packages/common/infra/src/page/record.ts +++ b/packages/common/infra/src/page/record.ts @@ -8,6 +8,7 @@ import type { Workspace, WorkspaceLocalState } from '../workspace'; export type PageMode = 'edgeless' | 'page'; export class PageRecord { + meta: Partial | null = null; constructor( public readonly id: string, private readonly workspace: Workspace, @@ -15,15 +16,14 @@ export class PageRecord { ) {} meta$ = LiveData.from>( - new Observable(subscriber => { + new Observable>(subscriber => { const emit = () => { - const meta = this.workspace.docCollection.meta.docMetas.find( - page => page.id === this.id - ); - if (meta === undefined) { - return; + if (this.meta === null) { + // getDocMeta is heavy, so we cache the doc meta reference + this.meta = + this.workspace.docCollection.meta.getDocMeta(this.id) || null; } - subscriber.next(meta); + subscriber.next({ ...this.meta }); }; emit(); diff --git a/packages/frontend/core/src/components/page-list/group-definitions.tsx b/packages/frontend/core/src/components/page-list/group-definitions.tsx index ee16687af9..4d67d4bd39 100644 --- a/packages/frontend/core/src/components/page-list/group-definitions.tsx +++ b/packages/frontend/core/src/components/page-list/group-definitions.tsx @@ -1,3 +1,4 @@ +import type { Tag } from '@affine/core/modules/tag'; import { TagService } from '@affine/core/modules/tag'; import { useAFFiNEI18N } from '@affine/i18n/hooks'; import { FavoritedIcon, FavoriteIcon } from '@blocksuite/icons'; @@ -28,7 +29,7 @@ const GroupLabel = ({ id, }: { id: string; - label: string; + label: ReactNode; count: number; icon?: ReactNode; }) => ( @@ -115,30 +116,38 @@ export const useDateGroupDefinitions = ( [key, t] ); }; + +const GroupTagLabel = ({ tag, count }: { tag: Tag; count: number }) => { + const tagValue = useLiveData(tag.value$); + const tagColor = useLiveData(tag.color$); + return ( + + } + > + ); +}; export const useTagGroupDefinitions = (): ItemGroupDefinition[] => { const tagService = useService(TagService); - const tagMetas = useLiveData(tagService.tagMetas$); + const tags = useLiveData(tagService.tags$); return useMemo(() => { - return tagMetas.map(tag => ({ + return tags.map(tag => ({ id: tag.id, - label: count => ( - - } - /> - ), + label: count => { + return ; + }, match: item => (item as DocMeta).tags?.includes(tag.id), })); - }, [tagMetas]); + }, [tags]); }; export const useFavoriteGroupDefinitions = < diff --git a/packages/frontend/core/src/hooks/affine/use-doc-engine-status.tsx b/packages/frontend/core/src/hooks/affine/use-doc-engine-status.tsx index bffcd4a02c..a4990bb991 100644 --- a/packages/frontend/core/src/hooks/affine/use-doc-engine-status.tsx +++ b/packages/frontend/core/src/hooks/affine/use-doc-engine-status.tsx @@ -4,8 +4,9 @@ import { useMemo } from 'react'; export function useDocEngineStatus() { const workspace = useService(Workspace); - const engineState = useLiveData(workspace.engine.docEngineState$); - + const engineState = useLiveData( + workspace.engine.docEngineState$.throttleTime(100) + ); const progress = (engineState.total - engineState.syncing) / engineState.total; diff --git a/packages/frontend/core/src/modules/multi-tab-sidebar/entities/tabs/journal.tsx b/packages/frontend/core/src/modules/multi-tab-sidebar/entities/tabs/journal.tsx index 71252aa9e6..d90a3ab0c0 100644 --- a/packages/frontend/core/src/modules/multi-tab-sidebar/entities/tabs/journal.tsx +++ b/packages/frontend/core/src/modules/multi-tab-sidebar/entities/tabs/journal.tsx @@ -196,11 +196,9 @@ const JournalDailyCountBlock = ({ date }: JournalBlockProps) => { (field: 'createDate' | 'updatedDate') => { return sortPagesByDate( pageRecords.filter(pageRecord => { - if (pageRecord.meta$.value.trash) return false; - return ( - pageRecord.meta$.value[field] && - dayjs(pageRecord.meta$.value[field]).isSame(date, 'day') - ); + const meta = pageRecord.meta$.value; + if (meta.trash) return false; + return meta[field] && dayjs(meta[field]).isSame(date, 'day'); }), field ); diff --git a/packages/frontend/core/src/pages/workspace/index.tsx b/packages/frontend/core/src/pages/workspace/index.tsx index 81b479a396..6e72b8c1eb 100644 --- a/packages/frontend/core/src/pages/workspace/index.tsx +++ b/packages/frontend/core/src/pages/workspace/index.tsx @@ -73,7 +73,7 @@ export const Component = (): ReactElement => { // avoid doing operation, before workspace is loaded const isRootDocReady = - useLiveData(workspace?.engine.rootDocState$)?.ready ?? false; + useLiveData(workspace?.engine.rootDocState$.map(v => v.ready)) ?? false; // if listLoading is false, we can show 404 page, otherwise we should show loading page. if (listLoading === false && meta === undefined) {