DataTable initialization gets slower after each destroy.
DataTable initialization gets slower after each destroy.
I am initializing the DataTables on an existing HTML table that is generated via another framework. The data in the table is controlled by that framework so when the data changes, I need to destroy the DataTables (to get the original table back) then get the rows updated and then initialize the DataTables again. This process works fine but everytime the data is updated, the initialization takes longer and longer. The initial load takes 2 seconds then 4, then 6, then 8.. I profiled the browser and seems like CPU is being utilized at 100% during the initialization. I am posting the screenshot of the browser profile here. Only thing I can see is that the "Listeners" accumulate and never cleared. Not sure if that is the culprit but looks like the other memory items (JS Heap, Documents and Nodes grow but they get cleared and after they are cleared, the processing time does not improve.
Answers
Why do you need to destroy the Datatables? Does the Datatable config change or just the DOM table data?
If just the table data changes maybe you can try
rows().invalidate()
with thedom
parameter to refresh the Datatable data cache.Kevin
Thanks Kevin for the answer. The invalidate works too but the issue is that the table loses the sorting capability after data is refreshed. Calling the draw() method after records are updated does not help either. Not sure if there are any other tricks to get the sorting back. The only way we can get the sorting back is to destroy and recreate which is causing the issue I described.
I do something similar. I use signalR to receive data on a periodic basis and update content for all clients. In my case, like yours, I need to update an existing table.
First in my JS file I have my table created with a "data": null setting. Basically just creating a table with an empty dataset, although you could have data as well.
Second, when my data is received/updated I do the following:
I don't have to destroy and recreate over and over and have not seen any degraded performance. I don't lose any of my initial sorting settings or capability.
Only issue that I have found, is that if a user is looking through the data it gets reset back to the first row view.
@glimpsed_chaos Thanks for the answer but in my case, I get the updates through variable binding in the basic HTML table in the DOM which gets parsed by DataTable on initialization. So not able to use the direct Data API of the DataTables to clear and add rows.
Then is sounds like invalidate isn't working because it should read the table and update the Datatables cache so that sorting and searching work.
Are you recreating the whole HTML table or just clearing and adding new data? If you are recreating the whole table then I can see that invalidate doesn't work as Datatables is not associated to the table anymore.
I guess we need to understand more about your process of replacing the data. Are you using
destroy()
before you update the HTML table? If not you might be leaving behind events, etc that aren't destroyed if you remove the HTML table before destroying.Please provide more info or better a link to your page to take a look.
Kevin
@kthorngren You are correct. Even though the data in the data tables is updated (I can see new rows) but the rows().data() returns the original set of data and does not get updated. invalidate seems to have no effect on getting the stored data refreshed.
Here's the step by step what I used to have (with the increasing initialization CPU time issue):
This works fine but step 4 is where I see increase in initialization every time the refresh happens. The first time its 2 seconds, then 4 then 6 then 8, ... (See the profile image above).
Per your recommendation, I modified the process to below:
I also tried to do invalidate().draw() after step 3 but no changes.
It's very strange.
For invalidate to work it would need to run after you updated the DOM based table. Specifically did you use
table.rows().invalidate('dom').draw();
?Where
table
is a variable containing the Datatable API.Your first set of steps seem like the correct order. Are you able to provide a link to your page or a test case replicating the issue?
https://datatables.net/manual/tech-notes/10#How-to-provide-a-test-case
Kevin
I spent more time drilling into processes in the profiler in chrome and finally realized the issue. I have a listener setup on 'draw.dt' which takes care of some styling. This listener sticks around even after the table is destroyed which seems to be a bug. What happens is that the draw event gets called internally during the initialization so every time the table is initialized, the handler is called from all previous initializations in addition to the current initialization. This leads to significant increase in the CPU time. The majority of the initialization is apparently was just the internal call to draw method which was causing my handler to be fired. Once I removed the handler, all initializations are equally in a matter of milliseconds. I think this is a bug but for now, I am going to find a better solution to apply my styling after the datatable is initialized or alternatively use the off to turn off the handler before destroying the table.
Thank you Kevin for your help and keeping me motivated to dig in
Good, glad you found it. @allan or @colin can take a closer look to see if they can replicate the issue to fix it.
Kevin
Looks like this is not a bug. It is documented:
"It is important to remove events from objects which no longer exist (before they are destroyed) to allow the Javascript engine's garbage collector to release the memory allocated for the events and the objects it has attached to."
However, @allan I still think once you destroy the DataTable, the listeners should be removed automatically to avoid getting into my scenario.
Nice find. I hadn't noticed that before. Lots of docs to read
Kevin
Hi @bms270 (and Kevin),
I'm not sure it is a bug. As you say, that quoted text states that if you add an event, it's up to you to remove it. The call to
destroy()
will remove all internal events, but the user may wish that events they created remain, especially if they're going to recreate the table as you are. One for @allan methinksCheers,
Colin
Yes, as Colin says, if you add event handlers, you are also responsible for removing them in order to prevent memory leaks, just as it works in the DOM.
Its possible we should have a namespace for events to automatically be removed on
destroy()
(we actually do already internally in the code, but it isn't publicly documented anywhere - I was worried about confusing things).Allan