From 3294043180322fdbabe9fa907e5d7f22c55980d6 Mon Sep 17 00:00:00 2001 From: Alex Yang Date: Fri, 7 Jul 2023 16:13:32 +0800 Subject: [PATCH] perf: reduce unused provider connection (#3090) --- apps/web/src/atoms/root.ts | 5 +-- .../components/affine/setting-modal/index.tsx | 26 ++++++++++++-- .../setting-modal/workspace-setting/index.tsx | 2 +- apps/web/src/layouts/workspace-layout.tsx | 22 +----------- packages/workspace/src/providers/index.ts | 34 +++++++++++-------- 5 files changed, 48 insertions(+), 41 deletions(-) diff --git a/apps/web/src/atoms/root.ts b/apps/web/src/atoms/root.ts index 328f214011..ee13f77641 100644 --- a/apps/web/src/atoms/root.ts +++ b/apps/web/src/atoms/root.ts @@ -8,6 +8,7 @@ import type { WorkspaceFlavour } from '@affine/env/workspace'; import { rootCurrentWorkspaceIdAtom, rootWorkspacesMetadataAtom, + workspaceAdaptersAtom, } from '@affine/workspace/atom'; import { assertExists } from '@blocksuite/global/utils'; import type { ActiveDocProvider } from '@blocksuite/store'; @@ -22,7 +23,7 @@ const logger = new DebugLogger('web:atoms:root'); */ export const workspacesAtom = atom>( async (get, { signal }) => { - const { WorkspaceAdapters } = await import('../adapters/workspace'); + const WorkspaceAdapters = get(workspaceAdaptersAtom); const flavours: string[] = Object.values(WorkspaceAdapters).map( plugin => plugin.flavour ); @@ -87,7 +88,7 @@ export const workspacesAtom = atom>( */ export const rootCurrentWorkspaceAtom = atom>( async (get, { signal }) => { - const { WorkspaceAdapters } = await import('../adapters/workspace'); + const WorkspaceAdapters = get(workspaceAdaptersAtom); const metadata = await get(rootWorkspacesMetadataAtom); const targetId = get(rootCurrentWorkspaceIdAtom); if (targetId === null) { diff --git a/apps/web/src/components/affine/setting-modal/index.tsx b/apps/web/src/components/affine/setting-modal/index.tsx index 466550b430..967ddcb274 100644 --- a/apps/web/src/components/affine/setting-modal/index.tsx +++ b/apps/web/src/components/affine/setting-modal/index.tsx @@ -5,8 +5,10 @@ import { import { WorkspaceFlavour } from '@affine/env/workspace'; import { useAFFiNEI18N } from '@affine/i18n/hooks'; import { ContactWithUsIcon } from '@blocksuite/icons'; +import type { PassiveDocProvider } from '@blocksuite/store'; +import { noop } from 'foxact/noop'; import type React from 'react'; -import { useCallback, useMemo } from 'react'; +import { useCallback, useEffect, useMemo } from 'react'; import { useCurrentWorkspace } from '../../../hooks/current/use-current-workspace'; import { useWorkspaces } from '../../../hooks/use-workspaces'; @@ -19,7 +21,7 @@ import { } from './general-setting'; import { SettingSidebar } from './setting-sidebar'; import { settingContent } from './style.css'; -import { WorkSpaceSetting } from './workspace-setting'; +import { WorkspaceSetting } from './workspace-setting'; type ActiveTab = GeneralSettingKeys | 'workspace' | 'account'; export type SettingProps = { @@ -70,6 +72,24 @@ export const SettingModal: React.FC = ({ onSettingClick({ activeTab: 'account', workspace: null }); }, [onSettingClick]); + useEffect(() => { + if (workspace && workspace !== currentWorkspace) { + const providers = workspace.blockSuiteWorkspace.providers.filter( + (provider): provider is PassiveDocProvider => + 'passive' in provider && provider.passive + ); + providers.forEach(provider => { + provider.connect(); + }); + return () => { + providers.forEach(provider => { + provider.disconnect(); + }); + }; + } + return noop; + }, [currentWorkspace, workspace]); + return ( = ({
{activeTab === 'workspace' && workspace ? ( - + ) : null} {generalSettingList.find(v => v.key === activeTab) ? ( diff --git a/apps/web/src/components/affine/setting-modal/workspace-setting/index.tsx b/apps/web/src/components/affine/setting-modal/workspace-setting/index.tsx index 5d6b29c981..3bb6af6e03 100644 --- a/apps/web/src/components/affine/setting-modal/workspace-setting/index.tsx +++ b/apps/web/src/components/affine/setting-modal/workspace-setting/index.tsx @@ -5,7 +5,7 @@ import { useOnTransformWorkspace } from '../../../../hooks/root/use-on-transform import { useAppHelper } from '../../../../hooks/use-workspaces'; import type { AllWorkspace } from '../../../../shared'; -export const WorkSpaceSetting = ({ +export const WorkspaceSetting = ({ workspace, }: { workspace: AllWorkspace; diff --git a/apps/web/src/layouts/workspace-layout.tsx b/apps/web/src/layouts/workspace-layout.tsx index 784871c0fd..18c5631205 100644 --- a/apps/web/src/layouts/workspace-layout.tsx +++ b/apps/web/src/layouts/workspace-layout.tsx @@ -99,27 +99,7 @@ export const QuickSearch: FC = () => { export const AllWorkspaceContext = ({ children, }: PropsWithChildren): ReactElement => { - const currentWorkspaceId = useAtomValue(rootCurrentWorkspaceIdAtom); - const workspaces = useWorkspaces(); - useEffect(() => { - const providers = workspaces - // ignore current workspace - .filter(workspace => workspace.id !== currentWorkspaceId) - .flatMap(workspace => - workspace.blockSuiteWorkspace.providers.filter( - (provider): provider is PassiveDocProvider => - 'passive' in provider && provider.passive - ) - ); - providers.forEach(provider => { - provider.connect(); - }); - return () => { - providers.forEach(provider => { - provider.disconnect(); - }); - }; - }, [currentWorkspaceId, workspaces]); + useWorkspaces(); return <>{children}; }; diff --git a/packages/workspace/src/providers/index.ts b/packages/workspace/src/providers/index.ts index 77bed9299a..43ef66a3a1 100644 --- a/packages/workspace/src/providers/index.ts +++ b/packages/workspace/src/providers/index.ts @@ -1,3 +1,4 @@ +import { DebugLogger } from '@affine/debug'; import type { LocalIndexedDBBackgroundProvider, LocalIndexedDBDownloadProvider, @@ -13,26 +14,25 @@ import { } from '@toeverything/y-indexeddb'; import type { Doc } from 'yjs'; -import { CallbackSet } from '../utils'; -import { localProviderLogger as logger } from './logger'; import { createSQLiteDBDownloadProvider, createSQLiteProvider, } from './sqlite-providers'; const Y = Workspace.Y; +const logger = new DebugLogger('indexeddb-provider'); const createIndexedDBBackgroundProvider: DocProviderCreator = ( id, blockSuiteWorkspace ): LocalIndexedDBBackgroundProvider => { const indexeddbProvider = create(blockSuiteWorkspace); - const callbacks = new CallbackSet(); + let connected = false; return { flavour: 'local-indexeddb-background', passive: true, get connected() { - return callbacks.ready; + return connected; }, cleanup: () => { indexeddbProvider.cleanup().catch(console.error); @@ -42,27 +42,27 @@ const createIndexedDBBackgroundProvider: DocProviderCreator = ( indexeddbProvider.connect(); indexeddbProvider.whenSynced .then(() => { - callbacks.ready = true; - callbacks.forEach(cb => cb()); + connected = true; }) .catch(error => { - callbacks.ready = false; + connected = false; if (error instanceof EarlyDisconnectError) { return; - } else { - throw error; } + throw error; }); }, disconnect: () => { assertExists(indexeddbProvider); logger.info('disconnect indexeddb provider', id); indexeddbProvider.disconnect(); - callbacks.ready = false; + connected = false; }, }; }; +const cache: WeakMap = new WeakMap(); + const createIndexedDBDownloadProvider: DocProviderCreator = ( id, doc @@ -74,11 +74,17 @@ const createIndexedDBDownloadProvider: DocProviderCreator = ( _reject = reject; }); async function downloadBinaryRecursively(doc: Doc) { - const binary = await downloadBinary(doc.guid); - if (binary) { + if (cache.has(doc)) { + const binary = cache.get(doc) as Uint8Array; Y.applyUpdate(doc, binary); - await Promise.all([...doc.subdocs].map(downloadBinaryRecursively)); + } else { + const binary = await downloadBinary(doc.guid); + if (binary) { + Y.applyUpdate(doc, binary); + cache.set(doc, binary); + } } + await Promise.all([...doc.subdocs].map(downloadBinaryRecursively)); } return { flavour: 'local-indexeddb', @@ -90,7 +96,7 @@ const createIndexedDBDownloadProvider: DocProviderCreator = ( // todo: cleanup data }, sync: () => { - logger.info('connect indexeddb provider', id); + logger.info('sync indexeddb provider', id); downloadBinaryRecursively(doc).then(_resolve).catch(_reject); }, };