From 47770ed7151ad0ba1cd8b77eb52590edd9ce9737 Mon Sep 17 00:00:00 2001 From: Shpuld Shpuldson Date: Wed, 17 Feb 2021 10:16:58 +0200 Subject: [PATCH 1/4] get rid of older messages when scrolling down in chat to keep it from bloating dom --- src/components/chat/chat.js | 1 + src/modules/chats.js | 6 ++++++ src/services/chat_service/chat_service.js | 17 +++++++++++++++++ 3 files changed, 24 insertions(+) diff --git a/src/components/chat/chat.js b/src/components/chat/chat.js index e57fcb91..f446f25b 100644 --- a/src/components/chat/chat.js +++ b/src/components/chat/chat.js @@ -241,6 +241,7 @@ const Chat = { this.fetchChat({ maxId: this.currentChatMessageService.minId }) } else if (this.bottomedOut(JUMP_TO_BOTTOM_BUTTON_VISIBILITY_OFFSET)) { this.jumpToBottomButtonVisible = false + this.$store.dispatch('cullOlderMessages', this.currentChatMessageService.chatId) if (this.newMessageCount > 0) { // Use a delay before marking as read to prevent situation where new messages // arrive just as you're leaving the view and messages that you didn't actually diff --git a/src/modules/chats.js b/src/modules/chats.js index 0a373d88..69d683bd 100644 --- a/src/modules/chats.js +++ b/src/modules/chats.js @@ -115,6 +115,9 @@ const chats = { }, handleMessageError ({ commit }, value) { commit('handleMessageError', { commit, ...value }) + }, + cullOlderMessages ({ commit }, chatId) { + commit('cullOlderMessages', chatId) } }, mutations: { @@ -227,6 +230,9 @@ const chats = { handleMessageError (state, { chatId, fakeId, isRetry }) { const chatMessageService = state.openedChatMessageServices[chatId] chatService.handleMessageError(chatMessageService, fakeId, isRetry) + }, + cullOlderMessages (state, chatId) { + chatService.cullOlderMessages(state.openedChatMessageServices[chatId]) } } } diff --git a/src/services/chat_service/chat_service.js b/src/services/chat_service/chat_service.js index e653ebc1..92ff689d 100644 --- a/src/services/chat_service/chat_service.js +++ b/src/services/chat_service/chat_service.js @@ -48,6 +48,22 @@ const deleteMessage = (storage, messageId) => { } } +const cullOlderMessages = (storage) => { + const maxIndex = storage.messages.length + const minIndex = maxIndex - 50 + if (maxIndex <= 50) return + + storage.messages = _.sortBy(storage.messages, ['id']) + storage.minId = storage.messages[minIndex].id + for (const message of storage.messages) { + if (message.id < storage.minId) { + delete storage.idIndex[message.id] + delete storage.idempotencyKeyIndex[message.idempotency_key] + } + } + storage.messages = storage.messages.slice(minIndex, maxIndex) +} + const handleMessageError = (storage, fakeId, isRetry) => { if (!storage) { return } const fakeMessage = storage.idIndex[fakeId] @@ -201,6 +217,7 @@ const ChatService = { empty, getView, deleteMessage, + cullOlderMessages, resetNewMessageCount, clear, handleMessageError From 7834ff52b1df539f27fd4f30efc0181fcc3d9995 Mon Sep 17 00:00:00 2001 From: Shpuld Shpuldson Date: Wed, 17 Feb 2021 10:53:38 +0200 Subject: [PATCH 2/4] add test --- .../services/chat_service/chat_service.spec.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/test/unit/specs/services/chat_service/chat_service.spec.js b/test/unit/specs/services/chat_service/chat_service.spec.js index 0251cae7..fbbca436 100644 --- a/test/unit/specs/services/chat_service/chat_service.spec.js +++ b/test/unit/specs/services/chat_service/chat_service.spec.js @@ -88,4 +88,21 @@ describe('chatService', () => { expect(view.map(i => i.type)).to.eql(['date', 'message', 'message', 'date', 'message']) }) }) + + describe('.cullOlderMessages', () => { + it('keeps 50 newest messages and idIndex matches', () => { + const chat = chatService.empty() + + for (let i = 100; i > 0; i--) { + // Use decimal values with toFixed to hack together constant length predictable strings + chatService.add(chat, { messages: [{ ...message1, id: 'a' + (i / 1000).toFixed(3), idempotency_key: i }] }) + } + chatService.cullOlderMessages(chat) + expect(chat.messages.length).to.eql(50) + expect(chat.messages[0].id).to.eql('a0.051') + expect(chat.minId).to.eql('a0.051') + expect(chat.messages[49].id).to.eql('a0.100') + expect(Object.keys(chat.idIndex).length).to.eql(50) + }) + }) }) From ee1cf36d523126630c20b0de0498207bafa14b3d Mon Sep 17 00:00:00 2001 From: Shpuld Shpuldson Date: Wed, 17 Feb 2021 10:54:14 +0200 Subject: [PATCH 3/4] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index cf4be7da..7b286f40 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### Changed - Display 'people voted' instead of 'votes' for multi-choice polls +- Optimized chat to not get horrible performance after keeping the same chat open for a long time ## [2.2.3] - 2021-01-18 ### Added From 67f3532ac95b2a8740ccbde581e74ac65eb20a9a Mon Sep 17 00:00:00 2001 From: Shpuld Shpuldson Date: Thu, 18 Feb 2021 10:14:45 +0200 Subject: [PATCH 4/4] add additional check with timeout --- src/components/chat/chat.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/components/chat/chat.js b/src/components/chat/chat.js index f446f25b..2780be75 100644 --- a/src/components/chat/chat.js +++ b/src/components/chat/chat.js @@ -234,6 +234,13 @@ const Chat = { const scrollable = this.$refs.scrollable return scrollable && scrollable.scrollTop <= 0 }, + cullOlderCheck () { + window.setTimeout(() => { + if (this.bottomedOut(JUMP_TO_BOTTOM_BUTTON_VISIBILITY_OFFSET)) { + this.$store.dispatch('cullOlderMessages', this.currentChatMessageService.chatId) + } + }, 5000) + }, handleScroll: _.throttle(function () { if (!this.currentChat) { return } @@ -241,7 +248,7 @@ const Chat = { this.fetchChat({ maxId: this.currentChatMessageService.minId }) } else if (this.bottomedOut(JUMP_TO_BOTTOM_BUTTON_VISIBILITY_OFFSET)) { this.jumpToBottomButtonVisible = false - this.$store.dispatch('cullOlderMessages', this.currentChatMessageService.chatId) + this.cullOlderCheck() if (this.newMessageCount > 0) { // Use a delay before marking as read to prevent situation where new messages // arrive just as you're leaving the view and messages that you didn't actually