perf(frontend): Notes Manager

This commit is contained in:
tamaina 2023-07-26 16:40:42 +00:00
parent ae949af6c3
commit e288d56181
1 changed files with 94 additions and 0 deletions

View File

@ -0,0 +1,94 @@
import { Note, UserLite } from "misskey-js/built/entities";
import { Ref, ref, ComputedRef, computed } from "vue";
import { api } from "./api";
export class EntitiyManager<T extends { id: string }> {
private entities: Map<T['id'], Ref<T>>;
constructor() {
this.entities = new Map();
}
public set(item: T): Ref<T> {
const cached = this.entities.get(item.id);
if (cached) {
cached.value = item;
} else {
this.entities.set(item.id, ref(item) as Ref<T>);
}
return this.get(item.id)!;
}
public get(id: string): Ref<T> | undefined {
return this.entities.get(id);
}
}
export const userLiteManager = new EntitiyManager<UserLite>();
type OmittedNote = Omit<Note, 'user' | 'renote' | 'reply'>;
type InternalCachedNote = Ref<OmittedNote>;
export class NoteManager {
private notes: Map<Note['id'], InternalCachedNote>;
private updatedAt: Map<Note['id'], number>;
private captureing: Map<Note['id'], number>;
constructor() {
this.notes = new Map();
this.updatedAt = new Map();
this.captureing = new Map();
}
public set(_note: Note): ComputedRef<Note> {
const note: Note = { ..._note };
userLiteManager.set(note.user);
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
//@ts-ignore
delete note.user;
if (note.renote) this.set(note.renote);
delete note.renote;
if (note.reply) this.set(note.reply);
delete note.reply;
const cached = this.notes.get(note.id);
if (cached) {
cached.value = note;
} else {
this.notes.set(note.id, ref(note));
}
this.updatedAt.set(note.id, Date.now());
return this.get(note.id)!;
}
public get(id: string): ComputedRef<Note> | undefined {
const note: InternalCachedNote | undefined = this.notes.get(id);
if (!note) return undefined;
return computed<Note>(() => {
const user = userLiteManager.get(note.value.userId)!;
const renote = note.value.renoteId ? this.get(note.value.renoteId) : undefined;
const reply = note.value.replyId ? this.get(note.value.replyId) : undefined;
return {
...note.value,
user: user.value,
renote: renote?.value,
reply: reply?.value,
};
});
}
public async fetch(id: string, force = false): Promise<ComputedRef<Note>> {
if (!force) {
const updatedAt = this.updatedAt.get(id);
if (updatedAt && Date.now() - updatedAt < 1000 * 30) {
const cachedNote = this.get(id);
if (cachedNote) {
return cachedNote as ComputedRef<Note>;
}
}
}
const fetchedNote = await api('notes/show', { noteId: id });
return this.set(fetchedNote);
}
}