computedを呼び出しごとに生成する(キャッシュしない)
This commit is contained in:
@@ -72,13 +72,6 @@ export class NoteManager {
|
|||||||
*/
|
*/
|
||||||
private notesSource: Ref<Map<Note['id'], CachedNoteSource>>;
|
private notesSource: Ref<Map<Note['id'], CachedNoteSource>>;
|
||||||
|
|
||||||
/**
|
|
||||||
* ソースからuser, renote, replyを取得したComputedRefのキャッシュを保持しておく
|
|
||||||
* nullは削除済みであることを表す
|
|
||||||
* キャプチャが0になったら削除される
|
|
||||||
*/
|
|
||||||
private notesComputed: Map<Note['id'], CachedNote>;
|
|
||||||
|
|
||||||
private updatedAt: Map<Note['id'], number>;
|
private updatedAt: Map<Note['id'], number>;
|
||||||
private captureing: Map<Note['id'], number>;
|
private captureing: Map<Note['id'], number>;
|
||||||
private connection: Stream | null;
|
private connection: Stream | null;
|
||||||
@@ -86,7 +79,6 @@ export class NoteManager {
|
|||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.notesSource = ref(new Map());
|
this.notesSource = ref(new Map());
|
||||||
this.notesComputed = new Map();
|
|
||||||
this.updatedAt = new Map();
|
this.updatedAt = new Map();
|
||||||
this.captureing = new Map();
|
this.captureing = new Map();
|
||||||
this.connection = $i ? useStream() : null;
|
this.connection = $i ? useStream() : null;
|
||||||
@@ -156,57 +148,53 @@ export class NoteManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public get(id: string): CachedNote {
|
public get(id: string): CachedNote {
|
||||||
if (!this.notesComputed.has(id)) {
|
// computedをキャッシュしたいけどバグるのでgetごとにcomputedを作成する
|
||||||
this.notesComputed.set(id, computed<Note | null>(() => {
|
|
||||||
const note = this.notesSource.value.get(id);
|
|
||||||
|
|
||||||
if (this.isDebuggerEnabled) console.log('NoteManager: compute note', id, note);
|
const result = computed<Note | null>(() => {
|
||||||
|
const note = this.notesSource.value.get(id);
|
||||||
|
|
||||||
if (!note) {
|
if (this.isDebuggerEnabled) console.log('NoteManager: compute note', id, note);
|
||||||
if (this.isDebuggerEnabled) console.log('NoteManager: compute note: source is null', id);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const user = userLiteManager.get(note.userId)!;
|
if (!note) {
|
||||||
|
if (this.isDebuggerEnabled) console.log('NoteManager: compute note: source is null', id);
|
||||||
const renote = note.renoteId ? this.get(note.renoteId) : undefined;
|
return null;
|
||||||
// renoteが削除されている場合はCASCADE削除されるためnullを返す
|
|
||||||
if (renote && !renote.value) {
|
|
||||||
if (this.isDebuggerEnabled) console.log('NoteManager: compute note: renote is null', id, note.renoteId);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const reply = note.replyId ? this.get(note.replyId) : undefined;
|
|
||||||
// replyが削除されている場合はCASCADE削除されるためnullを返す
|
|
||||||
if (reply && !reply.value) {
|
|
||||||
if (this.isDebuggerEnabled) console.log('NoteManager: compute note: reply is null', id, note.replyId);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const files = note.fileIds.map(id => driveFileManager.get(id)?.value);
|
|
||||||
|
|
||||||
const result = Object.assign({}, note, {
|
|
||||||
user: user.value,
|
|
||||||
renote: renote?.value ?? undefined,
|
|
||||||
reply: reply?.value ?? undefined,
|
|
||||||
files: files.filter(file => file) as DriveFile[],
|
|
||||||
});
|
|
||||||
|
|
||||||
if (this.isDebuggerEnabled) console.log('NoteManager: compute note: not null', id, result);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}));
|
|
||||||
if (this.isDebuggerEnabled) {
|
|
||||||
console.log('NoteManager: get note (new)', id, this.notesComputed.get(id));
|
|
||||||
console.trace();
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if (this.isDebuggerEnabled) {
|
const user = userLiteManager.get(note.userId)!;
|
||||||
console.log('NoteManager: get note (cached)', id, this.notesComputed.get(id), this.notesSource.value.get(id));
|
|
||||||
console.trace();
|
const renote = note.renoteId ? this.get(note.renoteId) : undefined;
|
||||||
|
// renoteが削除されている場合はCASCADE削除されるためnullを返す
|
||||||
|
if (renote && !renote.value) {
|
||||||
|
if (this.isDebuggerEnabled) console.log('NoteManager: compute note: renote is null', id, note.renoteId);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const reply = note.replyId ? this.get(note.replyId) : undefined;
|
||||||
|
// replyが削除されている場合はCASCADE削除されるためnullを返す
|
||||||
|
if (reply && !reply.value) {
|
||||||
|
if (this.isDebuggerEnabled) console.log('NoteManager: compute note: reply is null', id, note.replyId);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const files = note.fileIds.map(id => driveFileManager.get(id)?.value);
|
||||||
|
|
||||||
|
const result = {
|
||||||
|
...note,
|
||||||
|
user: user.value,
|
||||||
|
renote: renote?.value ?? undefined,
|
||||||
|
reply: reply?.value ?? undefined,
|
||||||
|
files: files.filter(file => file) as DriveFile[],
|
||||||
|
};
|
||||||
|
|
||||||
|
if (this.isDebuggerEnabled) console.log('NoteManager: compute note: not null', id, result);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
if (this.isDebuggerEnabled) {
|
||||||
|
console.log('NoteManager: get note (new)', id, result);
|
||||||
|
console.trace();
|
||||||
}
|
}
|
||||||
return this.notesComputed.get(id)!;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -282,21 +270,22 @@ export class NoteManager {
|
|||||||
public async fetch(id: string, force = false): Promise<CachedNote> {
|
public async fetch(id: string, force = false): Promise<CachedNote> {
|
||||||
if (this.isDebuggerEnabled) console.log('NoteManager: fetch note', id, { force });
|
if (this.isDebuggerEnabled) console.log('NoteManager: fetch note', id, { force });
|
||||||
|
|
||||||
|
const note = this.get(id);
|
||||||
|
|
||||||
if (!force) {
|
if (!force) {
|
||||||
const cachedNote = this.get(id);
|
if (note.value === null) {
|
||||||
if (cachedNote.value === null) {
|
|
||||||
// 削除されている場合はnullを返す
|
// 削除されている場合はnullを返す
|
||||||
if (this.isDebuggerEnabled) console.log('NoteManager: fetch note (deleted)', id, cachedNote.value);
|
if (this.isDebuggerEnabled) console.log('NoteManager: fetch note (deleted)', id, note.value);
|
||||||
return cachedNote;
|
return note;
|
||||||
}
|
}
|
||||||
// Renoteの場合はRenote元の更新日時も考慮する
|
// Renoteの場合はRenote元の更新日時も考慮する
|
||||||
const updatedAt = isRenote(cachedNote.value) ?
|
const updatedAt = isRenote(note.value) ?
|
||||||
this.updatedAt.get(id) :
|
this.updatedAt.get(id) :
|
||||||
Math.max(this.updatedAt.get(id) ?? 0, this.updatedAt.get(cachedNote.value!.renoteId!) ?? 0);
|
Math.max(this.updatedAt.get(id) ?? 0, this.updatedAt.get(note.value!.renoteId!) ?? 0);
|
||||||
// 2分以上経過していない場合はキャッシュを返す
|
// 2分以上経過していない場合はキャッシュを返す
|
||||||
if (cachedNote && updatedAt && Date.now() - updatedAt < 1000 * 120) {
|
if (note && updatedAt && Date.now() - updatedAt < 1000 * 120) {
|
||||||
if (this.isDebuggerEnabled) console.log('NoteManager: fetch note (use cache)', id, { cachedNote, updatedAt });
|
if (this.isDebuggerEnabled) console.log('NoteManager: fetch note (use cache)', id, { note, updatedAt });
|
||||||
return cachedNote;
|
return note;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this.isDebuggerEnabled) console.log('NoteManager: fetch note (fetch)', id);
|
if (this.isDebuggerEnabled) console.log('NoteManager: fetch note (fetch)', id);
|
||||||
@@ -304,14 +293,14 @@ export class NoteManager {
|
|||||||
.then(fetchedNote => {
|
.then(fetchedNote => {
|
||||||
if (this.isDebuggerEnabled) console.log('NoteManager: fetch note (success)', id, fetchedNote);
|
if (this.isDebuggerEnabled) console.log('NoteManager: fetch note (success)', id, fetchedNote);
|
||||||
this.set(fetchedNote);
|
this.set(fetchedNote);
|
||||||
return this.get(id)!;
|
return note;
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
if (this.isDebuggerEnabled) {
|
if (this.isDebuggerEnabled) {
|
||||||
console.error('NoteManager: fetch note (error)', id, err);
|
console.error('NoteManager: fetch note (error)', id, err);
|
||||||
}
|
}
|
||||||
// エラーが発生した場合は何もしない
|
// エラーが発生した場合は何もしない
|
||||||
return this.get(id)!;
|
return note;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -404,7 +393,6 @@ export class NoteManager {
|
|||||||
if (type !== 'deleted') {
|
if (type !== 'deleted') {
|
||||||
if (!note) throw new Error('NoteManager: onStreamNoteUpdated (update) note.value is null');
|
if (!note) throw new Error('NoteManager: onStreamNoteUpdated (update) note.value is null');
|
||||||
this.notesSource.value.set(id, { ...note, ...diff });
|
this.notesSource.value.set(id, { ...note, ...diff });
|
||||||
if (this.notesComputed.has(id)) triggerRef(this.notesComputed.get(id)!);
|
|
||||||
}
|
}
|
||||||
this.updatedAt.set(id, Date.now());
|
this.updatedAt.set(id, Date.now());
|
||||||
}
|
}
|
||||||
@@ -444,12 +432,6 @@ export class NoteManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.captureing.delete(id);
|
this.captureing.delete(id);
|
||||||
|
|
||||||
// キャプチャが終わったらcomputedキャッシュも消してしまう
|
|
||||||
if (!noDeletion) {
|
|
||||||
this.notesComputed.delete(id);
|
|
||||||
if (this.isDebuggerEnabled) console.log('NoteManager: decapture (delete computed)', id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user