We continue working on DataTableDev (check out our new demo with a new dataset)👐 , and we want to give you a glimpse of the backstage. In this article, we’ll explain how we used pseudo-multithreading and some callbacks to implement it.
It’s crucial to improve the user experience when working with data tables. It will boost productivity and lead to better results in analysis. Smooth navigation and animation, even with huge data volumes, are very important and are totally achievable!
If you haven’t read our previous articles, we recommend you to check them out as they explain a bit more about 💡how we came up with the idea of such a tool and what frames have to do with the optimization of data analytical processes. Since we explained the theory of frames and general approaches in the first two parts, we would like to delve into the practical implementation of some details this time.
To achieve smooth navigation (e.g., scrolling), the result needs to be rendered in a smooth and even fashion. Also, for the display to be graceful, a steady frame rate must be kept, therefore requiring maintaining each frame’s length alike. That way, the display won’t be choppy, jerky, or uneven without sudden jolts. While building our approach, we used pseudo-multithreading with two callbacks to help us.
☝️Avoiding extra redraws
requestAnimationFrame() is a method used to execute the rendering code on the next available screen repaint to avoid possible reflows caused by the recalculation of previously rendered elements. This means the drawing process is performed when changes are ready to be made, thus providing a more efficient repaint, resulting in smoother and more pleasant user interaction.
This is a great place to run code that doesn't deal with handling user input before redrawing directly. However, certain calculations should be avoided in the method, as this can lead to forced layout synchronization. In this phenomenon, the layout change happens before the styles are recalculated.
⚙️Optimizing the free time
requestIdleCallback() is an elegant way to identify the moment most appropriate for executing under-the-hood tasks, as well as predict how much time is left until the idle stage changes. Therefore it makes it possible to estimate whether a certain process can be completed at the given moment, then carrying out the procedures explicitly during idle times.
The main idea is to use the browser's time and resources as efficiently as possible; that way, we'll prioritize event handling, rendering, etc., and the script we pass to execute in
_requestIdleCallback()_will run when possible and have a lower priority than other processes.
In combination, these methods allow us to prioritize and optimize the execution of the tasks and fit in the constraint of 16.7 milliseconds per frame and maintain a steady frame rate. Nothing extra is done, and free time is used as productively as possible.
💡Why do we call it pseudo-multithreading?
The browser does not create a new thread, and the entire script (both main and secondary) is executed in one main thread. Suppose we schematically depict the order of calls. In that case, we will notice that the browser seems to switch between the main task and requestAnimationFrame() or requestIdleCallback() and executes them in its "free" time, and everything that does not have time is postponed until the next frame.
Both methods are open, and you can read the documentation to learn more about how they work.
😸What’s next?
You can check the real power of these ideas on one of our DataTable.dev demos and share some suggestions on how to improve it if you have some.
Top comments (4)
Wow! You are making great progress in development! Waiting for the final product)
thanks for sharing
I checked your demo. 1B records... Amazing. Good job, guys!
We are glad you liked it!