Room list: increase startup performance when rooms have notifications (#34358)

* Throttle section header update when listening to room notifications

* Update room list section header tests
This commit is contained in:
Florian Duros
2026-07-20 15:35:57 +00:00
committed by GitHub
parent f0c4f6a312
commit 475d16094c
2 changed files with 20 additions and 1 deletions
@@ -28,6 +28,7 @@ import {
import PosthogTrackers from "../../PosthogTrackers"; import PosthogTrackers from "../../PosthogTrackers";
import { CallStore, CallStoreEvent } from "../../stores/CallStore"; import { CallStore, CallStoreEvent } from "../../stores/CallStore";
import { type Call, CallEvent } from "../../models/Call"; import { type Call, CallEvent } from "../../models/Call";
import throttle from "lodash/throttle";
interface RoomListSectionHeaderViewModelProps { interface RoomListSectionHeaderViewModelProps {
tag: string; tag: string;
@@ -182,7 +183,17 @@ export class RoomListSectionHeaderViewModel
* Computes both the unread (bold) state and a merged notification decoration that aggregates * Computes both the unread (bold) state and a merged notification decoration that aggregates
* the rooms' notifications. The activity "dot" is intentionally excluded from the decoration. * the rooms' notifications. The activity "dot" is intentionally excluded from the decoration.
*/ */
private updateNotificationState = (): void => { private updateNotificationState = throttle(
(): void => {
this.doUpdateNotificationState();
},
200,
// Throttled because it iterates every room in the section and fires once per tracked room
// notification update, which during sync catch-up means once per incoming timeline event
{ leading: true, trailing: true },
);
private doUpdateNotificationState = (): void => {
let isUnread = false; let isUnread = false;
let isMention = false; let isMention = false;
let isNotification = false; let isNotification = false;
@@ -230,6 +241,7 @@ export class RoomListSectionHeaderViewModel
}; };
public dispose(): void { public dispose(): void {
this.updateNotificationState.cancel();
for (const state of this.roomNotificationStates) { for (const state of this.roomNotificationStates) {
state.off(NotificationStateEvents.Update, this.updateNotificationState); state.off(NotificationStateEvents.Update, this.updateNotificationState);
} }
@@ -250,11 +250,16 @@ describe("RoomListSectionHeaderViewModel", () => {
let notificationState: RoomNotificationState; let notificationState: RoomNotificationState;
beforeEach(() => { beforeEach(() => {
jest.useFakeTimers();
room = mkRoom(matrixClient, "!room:server"); room = mkRoom(matrixClient, "!room:server");
notificationState = new RoomNotificationState(room, false); notificationState = new RoomNotificationState(room, false);
jest.spyOn(RoomNotificationStateStore.instance, "getRoomState").mockReturnValue(notificationState); jest.spyOn(RoomNotificationStateStore.instance, "getRoomState").mockReturnValue(notificationState);
}); });
afterEach(() => {
jest.useRealTimers();
});
it("should set isUnread to false when no rooms have notifications", () => { it("should set isUnread to false when no rooms have notifications", () => {
const vm = new RoomListSectionHeaderViewModel({ const vm = new RoomListSectionHeaderViewModel({
tag: "m.favourite", tag: "m.favourite",
@@ -327,6 +332,7 @@ describe("RoomListSectionHeaderViewModel", () => {
jest.spyOn(notificationState, "hasAnyNotificationOrActivity", "get").mockReturnValue(true); jest.spyOn(notificationState, "hasAnyNotificationOrActivity", "get").mockReturnValue(true);
notificationState.emit(NotificationStateEvents.Update); notificationState.emit(NotificationStateEvents.Update);
jest.advanceTimersByTime(200);
expect(vm.getSnapshot().isUnread).toBe(true); expect(vm.getSnapshot().isUnread).toBe(true);
}); });
@@ -549,6 +555,7 @@ describe("RoomListSectionHeaderViewModel", () => {
jest.spyOn(notificationState, "isMention", "get").mockReturnValue(true); jest.spyOn(notificationState, "isMention", "get").mockReturnValue(true);
notificationState.emit(NotificationStateEvents.Update); notificationState.emit(NotificationStateEvents.Update);
jest.advanceTimersByTime(200);
expect(vm.getSnapshot().notification?.isMention).toBe(true); expect(vm.getSnapshot().notification?.isMention).toBe(true);
}); });
}); });