Performance tricks


When talking about performance, one should understand, that there are single-node operations that operate on single node... These ones are fast. The examples are: create a node, delete a node, move a node along the tree.

... And there are batch operations that touch a lot of nodes. The examples are: initial tree creation, moving a node from one tree to another which has different listeners, etc.

That performance issues become noticeable at 100-300 tree nodes depending on your trees. All algorithms are linear in worst case, but JS is slow language, DOM is also not that fast.

There is a number of features one could use to get a speedup.

Lazy loading

A node can be created with isFolder=true flag, but without children. Any node has a state, initially UNCHECKED for empty folder, and used by TreeLoadingController.

When a user presses expand, tree controller (supporting lazy loading) will send a request to server asking for nodes, and parse the answer creating children.

The benefit is obvious: you don't have to load/process whole tree at once. You can only load a single node and user will load the rest clicking "expand"

Lazy creation

Node/tree keeps array of its children in children property. Lazy creation is somewhat a half-way approach to lazy loading. It allows you to put data objects into this array and tree will create widgets of them later, when they are expanded.

For instance, one can call node.children = [{title:'node1'},{title:'node2'}]. The objects will be set, but no widgets are created. You can also set children to nested array: node.children = [{title:'node1', children:[{title:'node2'}] }].

You can create tree on server, JSON-serialize it and put to HTML, that is gzip-compressed. Compression will be 6 times or more, so it is not that space hungry.

The benefit comes from postponing almost all real job: widget creation and attaching it to tree will happen in expansion-time.

Comparison between lazy creation and lazy loading

  • You need web-service for lazy loading, not for lazy creation
  • No network waits for lazy creation
  • Lazy creation gives you the tree right here. You can search data objects and modify them without spending time and memory on graphical widgets

Sometimes, lazy creation and loading may work together nicely, providing seamless increase in speed and decrease in memory footprint. For instance, server may pass a whole tree branch in JSON to lazy loading controller. Top nodes will be created right along, because user needs them, but the rest of the branch will be postponed relying on lazy creation feature.

There are operations, like "expandAll" where such lazy tricks don't help. That is why widget creation process is well-optimized itself. createSimple is a hacky program-only way to create TreeNodes fast. setChildren is a method to assign (and create if needed) all children at once. It helps to evade some extra work happening when children are added one by one.

IE specific workaround

IE has a well-known bug. If an image was loaded dynamically - with a new Image(), or img.src= assignment, or even as a background of a new node, it will not be cached. So every time when you expand a node, all icons get loaded from server (or requested at least). A possible solution is to put a special div into HTML (adjust src to your path):

<div style="display:none">
  <!-- IE has a bug: it reloads all dynamically resolved images, no matter, is it 
  new Image() or CSS background. If you don't specify images like that,
  it will reload them every time a node is expanded -->
  <img src="../../../src/widget/templates/images/TreeV3/i.gif"/>
  <img src="../../../src/widget/templates/images/TreeV3/i_half.gif"/>
  <img src="../../../src/widget/templates/images/TreeV3/expand_minus.gif"/>
  <img src="../../../src/widget/templates/images/TreeV3/expand_plus.gif"/>
  <img src="../../../src/widget/templates/images/TreeV3/expand_leaf.gif"/>
  <img src="../../../src/widget/templates/images/TreeV3/i_long.gif"/>
  <img src="../../../src/widget/templates/images/TreeV3/document.gif"/>
  <img src="../../../src/widget/templates/images/TreeV3/open.gif"/>
  <img src="../../../src/widget/templates/images/TreeV3/closed.gif"/>
</div>