"๐๐ผ๐ ๐ฑ๐ผ ๐๐ผ๐ ๐ฝ๐ฟ๐ฒ๐๐ฒ๐ป๐ ๐จ๐ ๐น๐ฎ๐ด ๐๐ต๐ฒ๐ป ๐ฟ๐ฒ๐ฐ๐ฒ๐ถ๐๐ถ๐ป๐ด ๐ผ๐๐ฒ๐ฟ ๐ญ๐ฌ๐ฌ ๐ช๐ฒ๐ฏ๐ฆ๐ผ๐ฐ๐ธ๐ฒ๐ ๐ฒ๐๐ฒ๐ป๐๐ ๐ฝ๐ฒ๐ฟ ๐๐ฒ๐ฐ๐ผ๐ป๐ฑ?"
They clarified that the issue is not related to the server or backend but rather how to approach and resolve it on the frontend.
This made me think for a while, and then I realized that we often use these techniquesโknowingly or unknowingly. We are familiar with these concepts, but they often come with technical jargon.
Let me explain these techniques as simply as possible.
To stop UI lag from 100+ WebSocket events per second, you must decouple the high-frequency message stream from the main rendering thread.
Throttle or buffer the events, batch your DOM updates using requestAnimationFrame, and offload heavy processing to a Web Worker.
Implementing these targeted strategies will stabilize your frame rate:
1. Throttle or Buffer the Event Stream
Never update the UI on every single WebSocket message. At 100+ events per second, your browser is forced into constant layout recalculations (reflows) and repaints.
ย ย โข ๐ง๐ต๐ฟ๐ผ๐๐๐น๐ถ๐ป๐ด: Use libraries like Lodash to limit state updates to a maximum of 10โ15 frames per second
ย ย โข ๐๐๐ณ๐ณ๐ฒ๐ฟ๐ถ๐ป๐ด: Push incoming events into an array. Set up an interval or a requestAnimationFrame loop that drains this array, processes the aggregated data, and updates the UI once per cycle.
๐ฎ. ๐๐ฎ๐๐ฐ๐ต ๐๐ข๐ ๐จ๐ฝ๐ฑ๐ฎ๐๐ฒ๐
If you are updating UI components individually for every event, you will overwhelm the event loop.
ย ย โข Batch multiple data points into a single state update.
ย ย โข Use requestAnimationFrame to schedule your DOM updates so they align perfectly with the browser's refresh rate.
๐ฏ. ๐ข๐ณ๐ณ๐น๐ผ๐ฎ๐ฑ ๐๐ฒ๐ฎ๐๐ ๐ฃ๐ฟ๐ผ๐ฐ๐ฒ๐๐๐ถ๐ป๐ด ๐๐ผ ๐ฎ ๐ช๐ฒ๐ฏ ๐ช๐ผ๐ฟ๐ธ๐ฒ๐ฟ
ย ย โข If you need to parse, filter, or transform the incoming payload data before displaying it, do not do this on the main JavaScript thread.
ย ย โข Move your WebSocket connection and data parsing logic into a Web Worker.
ย ย โข The worker can handle the 100+ events per second, aggregate or reduce the data, and only send a condensed, render-ready payload back to the main UI thread periodically.
๐ฐ. ๐ข๐ฝ๐๐ถ๐บ๐ถ๐๐ฒ ๐ฅ๐ฒ๐ฎ๐ฐ๐๐ถ๐๐ถ๐๐ ๐ฎ๐ป๐ฑ ๐๐ผ๐บ๐ฝ๐ผ๐ป๐ฒ๐ป๐ ๐ฅ๐ฒ๐ป๐ฑ๐ฒ๐ฟ๐ถ๐ป๐ด
If you are using frameworks like React, Vue, or Angular, uncontrolled state updates will trigger massive re-render cascades.
ย ย โข ๐ฅ๐ฒ๐ฎ๐ฐ๐: Use useMemo and useCallback to prevent unnecessary component re-renders. Avoid storing rapidly changing WebSocket data directly in component state; instead, use a mutable ref for the raw data and sync to state on a throttled interval.
ย ย โข ๐ฉ๐ถ๐ฟ๐๐๐ฎ๐น๐ถ๐๐ฎ๐๐ถ๐ผ๐ป: If rendering these events in a list or table, use windowing libraries (like TanStack Table or Virtuoso) so the DOM only renders the rows currently visible on the screen.
๐ฑ. ๐จ๐๐ถ๐น๐ถ๐๐ฒ ๐๐ผ๐ฐ๐๐บ๐ฒ๐ป๐ ๐๐ฟ๐ฎ๐ด๐บ๐ฒ๐ป๐๐
For vanilla JavaScript implementations, avoid appending elements to the DOM in a loop. Instead, create a DocumentFragment, append your newly processed elements to it, and then append the entire fragment to the live DOM in one single operation
Top comments (0)