Best way to update an existing tree with new data

5,303 views
Skip to first unread message

foob...@gmail.com

unread,
Nov 17, 2014, 11:15:10 AM11/17/14
to jst...@googlegroups.com
Hi,

I use jsTree to display a generated tree. The tree data JSON is also generated and fed to the tree via the core.data parameter.
The fun part is that the tree can be modified by the user by altering the values in some input fields. When that happens, I send the values to the server, compute the new JSON there and update the tree.
Currently, I do this in a way that seems quite hackish to me: I set tree.settings.core.data to the new JSON and call tree.refresh().
Not only does that feel quite dirty, it's also quite slow in Firefox (Chrome is way faster).
Especially when those trees become large (some may have >10k nodes), a lot of time is spent inside $.jstree.core.prototype.redraw_node.
One of the issues is that I redraw the whole tree even if only a small portion of the data may have changed (unfortunately, I have no feasible way of knowing that as the users' input may or may not have quite drastic effects on the tree content).
First of all, am I even supposed to update the data that way or is there a better (as in more efficient) way to do that?

Thanks for your help,
Jochen

Ivan Bozhanov

unread,
Nov 18, 2014, 2:34:09 AM11/18/14
to jst...@googlegroups.com
The cleaner way to do it would be to set core.data to a function, something like:

var data = [... initial data ...];

$(..).jstree({
  core : {
    data : function (node, cb) {
      cb(data); // the var from above, which you can modify at any time
    }
})

// when you need to change the tree call:
$(...).jstree(true).refresh();

I doubt it will be faster, but at least it will be cleaner and future safe.
If you have very large trees consider some sort of lazy loading.
As for redraw_node - that should only be a problem if you have a really large flat list or a fully expanded tree - jstree tries to keep elements in the DOM to a minimum.

Best regards,
Ivan

foob...@gmail.com

unread,
Nov 18, 2014, 3:07:01 AM11/18/14
to jst...@googlegroups.com
Am Dienstag, 18. November 2014 08:34:09 UTC+1 schrieb Ivan Bozhanov:
The cleaner way to do it would be to set core.data to a function, something like:

var data = [... initial data ...];

$(..).jstree({
  core : {
    data : function (node, cb) {
      cb(data); // the var from above, which you can modify at any time
    }
})

// when you need to change the tree call:
$(...).jstree(true).refresh();

That looks much better, thank you. 

If you have very large trees consider some sort of lazy loading.

The loading is much less a problem than the rendering. If I only call tree.refresh() without actually changing the data, it takes almost as much time.
I can save some of that by setting forget_state to true. Something about the scroll offsets takes about 4 seconds on Firefox with a large tree, not sure if it's their getting or setting though.
Also, collapsing and expanding nodes is really slow with large fully expanded trees. Most of the time (93%) is spent inside jquery.event.special.focus.trigger
 
As for redraw_node - that should only be a problem if you have a really large flat list or a fully expanded tree

Yes, the latter unfortunately. A fully expanded tree of 1000+ nodes it not unusual. More that 30% are spent in redraw_node, parse_nest is at less than 20%.
 
jstree tries to keep elements in the DOM to a minimum.

I'll try to reduce them even more. I think the i elements for the icons can be replaced by a background-image on the anchor. That will shave off a third of the total number of elements and will remove the need to update the node text using innerHTML when the icon is already there.
Maybe I'll experiment with workers to see if I can speed things up some more.


Thanks for your help,
Jochen

foob...@gmail.com

unread,
Nov 18, 2014, 5:33:18 AM11/18/14
to jst...@googlegroups.com
Hi,


Am Dienstag, 18. November 2014 09:07:01 UTC+1 schrieb foob...@gmail.com:
I'll try to reduce them even more. I think the i elements for the icons can be replaced by a background-image on the anchor. That will shave off a third of the total number of elements and will remove the need to update the node text using innerHTML when the icon is already there.

That didn't help a lot. I monkey-patched the redraw_node method to do that but there was still a lot of time spent updating innerHTML.
I just tried another approach that looks promising:
I added a client-side cache (node text to rendered node) for leaf nodes. If the text does not change, I just clone a node from the cache and return that. Usually, that happens quite often, so I've been able to cut the total rendering time in half. I guess, I need to update some attributes  (id, aria-labelledby and such) though.
I wonder if it's possible to delay the rendering until the nodes are scrolled into view. I guess I'll give that a try when I find the time.

Jochen

Ivan Bozhanov

unread,
Nov 18, 2014, 9:14:20 AM11/18/14
to jst...@googlegroups.com
As far as performance goes - jstree has workers built-in that are enabled by default. You can make it 30% faster by disabling the workers (the delay is caused by the data transfer from and to the worker), but that means you will block the main UI thread - experiment with this setting if you want (core.worker: http://www.jstree.com/api/#/?q=worker&f=$.jstree.defaults.core.worker )
As for delaying drawing until the nodes are in view - I have thought about that, but I have not had the time to work on such a plugin - there are quite a few caveats - proper height although the nodes are not there, fast checks for nodes about to be visible, etc.

Keep in mind some plugins add extra DOM elements, and also - sometimes additional logic and rendering - which plugins do you have enabled?

Best regards,
Ivan

foob...@gmail.com

unread,
Nov 18, 2014, 9:32:48 AM11/18/14
to jst...@googlegroups.com
Thanks again for your help.


Am Dienstag, 18. November 2014 15:14:20 UTC+1 schrieb Ivan Bozhanov:
As far as performance goes - jstree has workers built-in that are enabled by default. You can make it 30% faster by disabling the workers (the delay is caused by the data transfer from and to the worker), but that means you will block the main UI thread - experiment with this setting if you want (core.worker: http://www.jstree.com/api/#/?q=worker&f=$.jstree.defaults.core.worker )

Yes, I have alredy turned them off. I understand those are only used for parsing the JSON and that is not the main problem currently. Drawing the nodes is.
 
As for delaying drawing until the nodes are in view - I have thought about that, but I have not had the time to work on such a plugin - there are quite a few caveats - proper height although the nodes are not there, fast checks for nodes about to be visible, etc.

Yes, that's definitely not going to be easy. But I assume it's the only way out of the performance issues with really large trees.
 

Keep in mind some plugins add extra DOM elements, and also - sometimes additional logic and rendering - which plugins do you have enabled?
 
The types and search plugins, but they only add about 5% to the rendering time.
As I said, a lot of time is spent updating the anchors' innerHTML in the redraw_node method. And there's probably not much we can do about that.

Jochen

Ivan Bozhanov

unread,
Nov 18, 2014, 9:47:37 AM11/18/14
to jst...@googlegroups.com
I will give the scroll plugin some more thought, in the mean time - have you tried using the force_text setting - if it is true innerHTML won't be touched, although I doubt creating and appending a text node will be much faster. I have not noticed a lot of delay in large trees but I will make a few tests - I have not tested large trees in a few versions, maybe I broke something along the way.

Ivan

foob...@gmail.com

unread,
Nov 18, 2014, 9:51:06 AM11/18/14
to jst...@googlegroups.com
Am Dienstag, 18. November 2014 15:47:37 UTC+1 schrieb Ivan Bozhanov:
I will give the scroll plugin some more thought,

Thank you! If you decide to write it and need a beta tester, just let me know.
 
in the mean time - have you tried using the force_text setting - if it is true innerHTML won't be touched, although I doubt creating and appending a text node will be much faster.

Yes, I've tried it, it doesn't make much of a difference. Also, I have HTML in my node texts.

Jochen
Reply all
Reply to author
Forward
0 new messages