From 7dbffb348dfe8fbd83c9ea4bff9f37292b0979bb Mon Sep 17 00:00:00 2001 From: David Baker Date: Fri, 30 Jan 2026 17:09:02 +0000 Subject: [PATCH] Throttle notification state calculation (#31922) Because every room in a space will emit a notification state change when push rules change so we would otherwise recalculate the space notification state for every room in the space, On^2 style. --- .../notifications/SpaceNotificationState.ts | 35 +++++++++++-------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/src/stores/notifications/SpaceNotificationState.ts b/src/stores/notifications/SpaceNotificationState.ts index 0faf8bc3e6..66907b7816 100644 --- a/src/stores/notifications/SpaceNotificationState.ts +++ b/src/stores/notifications/SpaceNotificationState.ts @@ -6,6 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com Please see LICENSE files in the repository root for full details. */ +import { throttle } from "lodash"; import { type Room } from "matrix-js-sdk/src/matrix"; import { NotificationLevel } from "./NotificationLevel"; @@ -63,23 +64,27 @@ export class SpaceNotificationState extends NotificationState { this.calculateTotalState(); }; - private calculateTotalState(): void { - const snapshot = this.snapshot(); + private calculateTotalState = throttle( + (): void => { + const snapshot = this.snapshot(); - this._count = 0; - this._level = NotificationLevel.None; - for (const [roomId, state] of Object.entries(this.states)) { - const room = this.rooms.find((r) => r.roomId === roomId); - const roomTags = room ? RoomListStore.instance.getTagsForRoom(room) : []; + this._count = 0; + this._level = NotificationLevel.None; + for (const [roomId, state] of Object.entries(this.states)) { + const room = this.rooms.find((r) => r.roomId === roomId); + const roomTags = room ? RoomListStore.instance.getTagsForRoom(room) : []; - // We ignore unreads in LowPriority rooms, see https://github.com/vector-im/element-web/issues/16836 - if (roomTags.includes(DefaultTagID.LowPriority) && state.level === NotificationLevel.Activity) continue; + // We ignore unreads in LowPriority rooms, see https://github.com/vector-im/element-web/issues/16836 + if (roomTags.includes(DefaultTagID.LowPriority) && state.level === NotificationLevel.Activity) continue; - this._count += state.count; - this._level = Math.max(this.level, state.level); - } + this._count += state.count; + this._level = Math.max(this.level, state.level); + } - // finally, publish an update if needed - this.emitIfUpdated(snapshot); - } + // finally, publish an update if needed + this.emitIfUpdated(snapshot); + }, + 100, + { leading: false, trailing: true }, + ); }