Memoize derive calls

If we call files() 90 odd times, it will create 90 different derived stores. This means that we're going to do an awful lot of extra work as each update to the selected ids will trigger 90 jobs.

By memoizing the store, we will only ever create one derived object and as such eliminate the dupilcate work.
This commit is contained in:
Caleb Owens 2024-06-04 19:59:30 +02:00
parent 95eca10174
commit d89281fdcc
No known key found for this signature in database
5 changed files with 47 additions and 27 deletions

View File

@ -20,6 +20,7 @@
import lscache from 'lscache';
import { setContext } from 'svelte';
import { quintOut } from 'svelte/easing';
import { writable } from 'svelte/store';
import { slide } from 'svelte/transition';
export let branch: Branch;
@ -50,10 +51,12 @@
const project = getContext(Project);
const fileIdSelection = new FileIdSelection();
const branchFiles = writable(branch.files);
$: branchFiles.set(branch.files);
const fileIdSelection = new FileIdSelection(project.id, branchFiles);
setContext(FileIdSelection, fileIdSelection);
$: selectedFile = fileIdSelection.selectedFile(branch.files, project.id);
$: selectedFile = fileIdSelection.selectedFile;
const userSettings = getContextStoreBySymbol<Settings>(SETTINGS);

View File

@ -1,7 +1,6 @@
<script lang="ts">
import FileContextMenu from './FileContextMenu.svelte';
import FileStatusIcons from './FileStatusIcons.svelte';
import { Project } from '$lib/backend/projects';
import Checkbox from '$lib/components/Checkbox.svelte';
import { draggable } from '$lib/dragging/draggable';
import { DraggableFile } from '$lib/dragging/draggables';
@ -24,10 +23,9 @@
const branch = maybeGetContextStore(Branch);
const selectedOwnership: Writable<Ownership> | undefined = maybeGetContextStore(Ownership);
const fileIdSelection = getContext(FileIdSelection);
const project = getContext(Project);
const commit = getCommitStore();
$: selectedFiles = fileIdSelection.files($branch?.files || [], project.id);
const selectedFiles = fileIdSelection.files;
let checked = false;
let indeterminate = false;

View File

@ -13,6 +13,7 @@
import lscache from 'lscache';
import { marked } from 'marked';
import { onMount, setContext } from 'svelte';
import { writable } from 'svelte/store';
import type { PullRequest } from '$lib/github/types';
export let branch: RemoteBranch;
@ -21,10 +22,10 @@
const project = getContext(Project);
const baseBranch = getContextStore(BaseBranch);
const fileIdSelection = new FileIdSelection();
const fileIdSelection = new FileIdSelection(project.id, writable([]));
setContext(FileIdSelection, fileIdSelection);
$: selectedFile = fileIdSelection.selectedFile([], project.id);
$: selectedFile = fileIdSelection.selectedFile;
const defaultBranchWidthRem = 30;
const laneWidthKey = 'branchPreviewLaneWidth';

View File

@ -1,6 +1,6 @@
import { isDefined } from '$lib/utils/typeguards';
import { listRemoteCommitFiles } from '$lib/vbranches/remoteCommits';
import { derived } from 'svelte/store';
import { derived, type Readable } from 'svelte/store';
import type { AnyFile, LocalFile } from '$lib/vbranches/types';
export interface FileKey {
@ -32,7 +32,11 @@ export class FileIdSelection {
private value: string[];
private callbacks: CallBack[];
constructor(value: FileKey[] = []) {
constructor(
private projectId: string,
private localFiles: Readable<LocalFile[]>,
value: FileKey[] = []
) {
this.callbacks = [];
this.value = value.map((key) => stringifyFileKey(key.fileId, key.commitId));
}
@ -87,24 +91,36 @@ export class FileIdSelection {
return fileKey;
}
selectedFile(localFiles: LocalFile[], branchId: string) {
return derived(this, async (value): Promise<AnyFile | undefined> => {
if (value.length !== 1) return;
const fileKey = parseFileKey(value[0]);
return await findFileByKey(localFiles, branchId, fileKey);
});
#selectedFile: Readable<Promise<AnyFile | undefined>> | undefined;
get selectedFile() {
this.#selectedFile ||= derived(
[this as Readable<string[]>, this.localFiles],
async ([selection, localFiles]): Promise<AnyFile | undefined> => {
if (selection.length !== 1) return;
const fileKey = parseFileKey(selection[0]);
return await findFileByKey(localFiles, this.projectId, fileKey);
}
);
return this.#selectedFile;
}
files(localFiles: LocalFile[], branchId: string) {
return derived(this, async (value) => {
const files = await Promise.all(
value.map(async (fileKey) => {
return await findFileByKey(localFiles, branchId, parseFileKey(fileKey));
})
);
#files: Readable<Promise<AnyFile[]>> | undefined;
get files() {
this.#files ||= derived(
[this as Readable<string[]>, this.localFiles],
async ([selection, localFiles]): Promise<AnyFile[]> => {
const files = await Promise.all(
selection.map(async (fileKey) => {
return await findFileByKey(localFiles, this.projectId, parseFileKey(fileKey));
})
);
return files.filter(isDefined);
});
return files.filter(isDefined);
}
);
return this.#files;
}
get length() {
@ -112,7 +128,7 @@ export class FileIdSelection {
}
}
export async function findFileByKey(localFiles: LocalFile[], projectId: string, key: FileKey) {
async function findFileByKey(localFiles: LocalFile[], projectId: string, key: FileKey) {
if (key.commitId) {
const remoteFiles = await listRemoteCommitFiles(projectId, key.commitId);
return remoteFiles.find((file) => file.id === key.fileId);

View File

@ -11,6 +11,8 @@
import { FileIdSelection } from '$lib/vbranches/fileIdSelection';
import lscache from 'lscache';
import { onMount, setContext } from 'svelte';
import { writable } from 'svelte/store';
const defaultBranchWidthRem = 30;
const laneWidthKey = 'historyLaneWidth';
const userSettings = getContextStoreBySymbol<Settings>(SETTINGS);
@ -19,10 +21,10 @@
const baseBranch = baseBranchService.base;
const project = getContext(Project);
const fileIdSelection = new FileIdSelection();
const fileIdSelection = new FileIdSelection(project.id, writable([]));
setContext(FileIdSelection, fileIdSelection);
$: selectedFile = fileIdSelection.selectedFile([], project.id);
$: selectedFile = fileIdSelection.selectedFile;
let rsViewport: HTMLDivElement;
let laneWidth: number;