perf(frontend): Notes Manager
This commit is contained in:
parent
ae949af6c3
commit
e288d56181
packages/frontend/src/scripts
|
@ -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);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue