Keep 5-second delay between renders to withstand message floods

Instead of rendering the message list every time a message comes
in, we give a delay of 5 seconds. If more messages have arrived in
the meantime, those messages will also get included in the render.

5 seconds is selected to offer the best performance; if it ends
up being too long we could later make it configurable or bring it
down to something like 1 second. Another option is to intelligently
ramp up the delays as messages flood in, and then ramp it down when
the flow reduces to just 1-2 messages. But all that is for another
day ;)

This commit hopefully addresses #10; it should theoretically work
but I haven't been able to fully test it yet due to not yet
receiving a full flood of messages :P
This commit is contained in:
Badri Sunderarajan 2024-03-23 13:55:01 +05:30
parent 8d1ca787fa
commit 1f7ad1408c
Signed by: badrihippo
GPG key ID: 9F594532AD60DE03

View file

@ -43,27 +43,64 @@
}
}), 1000)
// Stores information on the rendered chatboxes
let chatboxes = []
let chatboxesRenderedAt = 0 // a very, very long time ago
let chatboxesRendering = false // is a rendering scheduled?
// TODO: use a sliding window so that only the chatboxes
// that are in view get rendered
// Helper function to convert chatboxes into
// (exceedingly lightweight) object array for
// final rendering
function chatboxesToArray(chatboxes) {
if (!chatboxes) return []
return _converse.chatboxes.models.map(c => ({
return chatboxes.models.map(c => ({
id: c.id,
title: c.attributes.name || c.attributes.id,
lastMessage: c.messages?.last()?.attributes?.body,
}))
}
let chatboxes = chatboxesToArray(_converse?.chatboxes)
function renderChatboxes() {
// If the chatboxes are empty, just render an empty array
if (!_converse?.chatboxes) {
chatboxes = []
return
}
// If the chatboxes were updated more than 5 seconds ago,
// render them again immediately
if (new Date() - chatboxesRenderedAt > 5000) {
chatboxes = chatboxesToArray(_converse?.chatboxes)
} else {
// If they were updated less than 5 seconds ago, check
// if a re-render has been scheduled
if (chatboxesRendering) {
return
} else {
chatboxesRendering = true
// Render them after a gap
setTimeout(function () {
chatboxesRendering = false
chatboxesRenderedAt = new Date()
renderChatboxes()
}, 5000)
}
}
}
// Render them once
renderChatboxes()
_converse.on('chatBoxesFetched', () => {
chatboxes = chatboxesToArray(_converse.chatboxes)
renderChatboxes()
})
_converse.on('message', () => {
chatboxes = chatboxesToArray(_converse.chatboxes)
renderChatboxes()
})
</script>