Switch to an internal Map for previews
This means we're abusing the AsyncStoreWithClient to get access to a lifecycle, but overall that seems like a minor crime compared to the time spend abusing the store's state as a map. With thousands of rooms shown, we can save on average 743ms per preview. The new preview time is 0.12ms on average.pull/21833/head
parent
67fd6e6122
commit
d593d24aea
|
@ -26,6 +26,7 @@ import { CallAnswerEventPreview } from "./previews/CallAnswerEventPreview";
|
|||
import { CallHangupEvent } from "./previews/CallHangupEvent";
|
||||
import { StickerEventPreview } from "./previews/StickerEventPreview";
|
||||
import { ReactionEventPreview } from "./previews/ReactionEventPreview";
|
||||
import { UPDATE_EVENT } from "../AsyncStore";
|
||||
|
||||
const PREVIEWS = {
|
||||
'm.room.message': {
|
||||
|
@ -62,12 +63,15 @@ type TAG_ANY = "im.vector.any";
|
|||
const TAG_ANY: TAG_ANY = "im.vector.any";
|
||||
|
||||
interface IState {
|
||||
[roomId: string]: Map<TagID | TAG_ANY, string | null>; // null indicates the preview is empty / irrelevant
|
||||
// Empty because we don't actually use the state
|
||||
}
|
||||
|
||||
export class MessagePreviewStore extends AsyncStoreWithClient<IState> {
|
||||
private static internalInstance = new MessagePreviewStore();
|
||||
|
||||
// null indicates the preview is empty / irrelevant
|
||||
private previews = new Map<string, Map<TagID|TAG_ANY, string|null>>();
|
||||
|
||||
private constructor() {
|
||||
super(defaultDispatcher, {});
|
||||
}
|
||||
|
@ -85,10 +89,9 @@ export class MessagePreviewStore extends AsyncStoreWithClient<IState> {
|
|||
public getPreviewForRoom(room: Room, inTagId: TagID): string {
|
||||
if (!room) return null; // invalid room, just return nothing
|
||||
|
||||
const val = this.state[room.roomId];
|
||||
if (!val) this.generatePreview(room, inTagId);
|
||||
if (!this.previews.has(room.roomId)) this.generatePreview(room, inTagId);
|
||||
|
||||
const previews = this.state[room.roomId];
|
||||
const previews = this.previews.get(room.roomId);
|
||||
if (!previews) return null;
|
||||
|
||||
if (!previews.has(inTagId)) {
|
||||
|
@ -101,11 +104,10 @@ export class MessagePreviewStore extends AsyncStoreWithClient<IState> {
|
|||
const events = room.timeline;
|
||||
if (!events) return; // should only happen in tests
|
||||
|
||||
let map = this.state[room.roomId];
|
||||
let map = this.previews.get(room.roomId);
|
||||
if (!map) {
|
||||
map = new Map<TagID | TAG_ANY, string | null>();
|
||||
|
||||
// We set the state later with the map, so no need to send an update now
|
||||
this.previews.set(room.roomId, map);
|
||||
}
|
||||
|
||||
// Set the tags so we know what to generate
|
||||
|
@ -141,16 +143,15 @@ export class MessagePreviewStore extends AsyncStoreWithClient<IState> {
|
|||
}
|
||||
|
||||
if (changed) {
|
||||
// Update state for good measure - causes emit for update
|
||||
// noinspection JSIgnoredPromiseFromCall - the AsyncStore handles concurrent calls
|
||||
this.updateState({[room.roomId]: map});
|
||||
// We've muted the underlying Map, so just emit that we've changed.
|
||||
this.emit(UPDATE_EVENT, this);
|
||||
}
|
||||
return; // we're done
|
||||
}
|
||||
|
||||
// At this point, we didn't generate a preview so clear it
|
||||
// noinspection JSIgnoredPromiseFromCall - the AsyncStore handles concurrent calls
|
||||
this.updateState({[room.roomId]: null});
|
||||
this.previews.delete(room.roomId);
|
||||
this.emit(UPDATE_EVENT, this);
|
||||
}
|
||||
|
||||
protected async onAction(payload: ActionPayload) {
|
||||
|
|
Loading…
Reference in New Issue