As your app grows, its quite common to face performance issues. Such as slow animations or transitions, janked scrolling and hung up UI in worst scenarios.
It all boils down to one thing, that you are not able to retain 60 FPS(frames per second). Its the golden number every JS or frontend developer should be familiar with. Lets do some math and see what it is.
1 second = 1000 milliseconds
1000/60 = ~16.6 milliseconds
So you have only ~16.6 milliseconds to render 1 frame, in order for your app to feel silky smooth.
App feels laggy when the fps drops below 30.
1000/30 = ~33.3 milliseconds
That is your frame is taking more than just 33.3 milliseconds to render. Maybe you are doing some costly operations, like huge amount of data processing or animations. Your target should be between 30 fps to 60 fps (the more the better) all the time.
Call Stack > Render Queue > Callback queue
As the code runs, the functions you call are pushed on to the call stack. When they are done, they are popped from that stack.
So your target is to process everything in stack within ~16 to ~33 ms. If any function stays more than 33ms on the call stack, render queue doesn’t get its turn to repaint the screen.
There are multiple ways to make call stack less busy. For starters you should do most of the heavy lifting async. The priority of Render queue is more than callback queue. Unlike call stack, callback queue gives turn to the render queue to repaint the screen before processing every callback. For huge data sets you can do batch processing with multiple async callbacks.
Lastly prefer requestAnimationFrame over setTimeout or setInterval for animations.
Don’t occupy call stack for long.
Use async to relieve call stack.
Batch processing with multiple async callbacks for large datasets.