martedì 22 luglio 2008

DOM DocumentFragments

Questo Post prende spunto dall'articolo di John Resig che tratta i DOM DocumentFragments.

I DOM DocumentFragments sono dei contenitori lightweight (letteralmente "peso-leggero" cioe' semplificati,leggeri)che possono contenere dei nodi del Document Object Model (DOM).

Fanno parte delle specifiche ufficiali "DOM 1", quindi sono supportati nei browser recenti (a partire ad esempio da IE6).

Ma perche' possono diventare utilissimi ad uno sviluppatore di web applications?

Osservando meglio le specifiche si nota che:

"Furthermore, various operations -- such as inserting nodes as children of another Node -- may take DocumentFragment objects as arguments; this results in all the child nodes of the DocumentFragment being moved to the child list of this node"

ovvero cio' significa che se prendiamo un set di nodi del DOM e lo aggiungiamo ad un frammento (fragment) allora possiamo aggiungere il frammento al documento, invece di aggiungere ogni nodo singolarmente.

Nel far questo si ottiene una migliore performance complessiva, avendo a disposizione anche il metodo cloneNode nell'oggetto DocumentFragments. Questo perche' e' meno costoso aggiungere i nodi al frammento, essendo un oggetto molto piu' piccolo dell'intero DOM che invece ad ogni inserimento deve essere "risistemato".

Supponiamo di avere un blocco di nodi DOM che vogliamo inserire in un semplice documento:

var elems = [
document.createElement("hr"),
text( document.createElement("b"), "Links:" ),
document.createTextNode(" "),
text( document.createElement("a"), "Link A" ),
document.createTextNode(" | "),
text( document.createElement("a"), "Link B" ),
document.createTextNode(" | "),
text( document.createElement("a"), "Link C" )
];


function text(node, txt){
node.appendChild( document.createTextNode(txt) );
return node;
}


Se vogliamo aggiungere questi nodi nel nostro documento probabilmente lo faremmo nel modo tradizionale: con un ciclo che scorre i nodi, li clona individualmente (cosicche' possiamo continuare ad aggiungerli attraverso tutto il documento):

var div = document.getElementsByTagName("div");


for ( var i = 0; i < div.length; i++ ) {
for ( var e = 0; e < elems.length; e++ ) {
div[i].appendChild( elems[e].cloneNode(true) );
}
}

DocumentFragments Append

Invece quando consideriamo l'uso dell'oggetto DocumentFragments possiamo subito vedere una diversa struttura. Per iniziare aggiungiamo tutti i nostri nodi nel frammento stesso, costruito usando il metodo createDocumentFragment.

Poi il punto interessante arriva quando e' ora di inserire effettivamente i nodi dentro il documento: dobbiamo solo chiamare appendChild e cloneNode una volta sola per tutti i nodi!

var div = document.getElementsByTagName("div");


var fragment = document.createDocumentFragment();
for ( var e = 0; e < elems.length; e++ ) {
fragment.appendChild( elems[e] );
}

for ( var i = 0; i < div.length; i++ ) {
div[i].appendChild( fragment.cloneNode(true) );
}
Facendo qualche misurazione su una pagina di demo si ottiengono risultati analoghi a questi:

Browser      Normal (ms) Fragment (ms)
Firefox 3.0.1      90                47
Safari 3.1.2        156               44
Opera 9.51        208               95
IE 6                      401             140
IE 7                     230                61
IE 8b1                 120               40