tags:

views:

161

answers:

2

Being interested in building html chunks off-dom before to insert them in the dom, I have done some testing using dynatrace. I used bobince's method : http://stackoverflow.com/questions/1643349/is-there-any-way-to-find-an-element-in-a-documentfragment/1643512#1643512

I found it to be almost 1000 time slower (in IE7), which surprised me a lot.

Since the function is pretty basic, I was wondering about the strategy used by engines such as sizzle.

I would like to know if there is some more efficient ways to do context-based node selection ?

+1  A: 

Framework selector engines are generally evaluated right-hand-first, so I would expect a contextual ID selector to document.getElementById the ID and then check to see whether the results were in the context node by stepping up the parentNodes. This is reasonably fast, but it won't work for out-of-Document DOM trees like this example. Selector engines then would have to do it the desperately slow way, or not care (eg. Sizzle doesn't work with DocumentFragment).

There is a better way of getting the ID inside a fragment I've remembered since then, for browsers that implement Selectors-API (IE8, Firefox 3.5, Opera 10, Safari 3.1, Chrome 3). You can use querySelector to apply a CSS selector with the DocumentFragment as a context node, as the API requires DocumentFragment implements NodeSelector:

alert(frag.querySelector('#myId'))

This isn't quite as fast as getElementById, but it's loads better than the DOM version.

Unfortunately most frameworks that have Selectors-API optimisations won't use them in this case or any others with context nodes, because the way the context node works is different in querySelector[All] to how the frameworks traditionally implemented it, making them incompatible.

Selectors-API Level 2 proposes ‘scoped’ methods that behave like the traditional framework selectors... it'll be a while before that's usable, but we probably won't see optimised contextual selectors in the existing frameworks until then. I think this is a shame, as although the querySelector method of using the context node for filtering but not scoping is not quite as good, it's still pretty much usable for all the common cases.

bobince
Are you sure about `Element.getElementById`? The whole premise of contextual selection by id is wrong IMHO. An id is unique in a `Document` context, not in an `Element` or `DocumentFragment`.
Chetan Sastry
Oh yes. I do appear to be lying, and thinking of getElementsByTagName. Oops! Updating... I've found some more stuff to play with :-)
bobince
Ah. I was shocked that I could have missed something like Element.getElementById(). I read some stuff about querySelector, but I have to focus on IE7. @Chetan the point is to perform selection on html that is not in dom yet.
Olivvv
Framework selector engines such as sizzle do work on offdom elements. It is common practice for jqueryists to build the html offDom and insert it once it is finished. I believe it using createElement() rather than createDocumentFragment()
Olivvv
A: 

If you don't mind inserting your documentFragment into DOM temporarily...

function getElementFromFragById(frag, id) {
    var tempDiv = document.createElement("div");
    tempDiv.style.display = "none";
    tempDiv.appendChild(frag);
    document.body.appendChild(tempDiv);
    var elem = document.getElementById(id);
    document.body.removeChild(tempDiv);
    return document.getElementById(id) ? null : elem; //if the element still exists, we have a problem
}

This works reliably as long as your documentFragment doesn't contain elements with id that already exist in document and you want to search on that id.

Chetan Sastry
I want to manipulate html off dom essentially in order to avoid reflows, which are a big performance cost. Unfortunately IE7 does reflow when hidden elements are affected. See http://www.phpied.com/the-new-game-show-will-it-reflow/ On a side note I m not sure the fragment is still a fragment when going through your function, so that would probably cancel the performance gains from using a fragment. Anyway I m here interested in off-dom operations, so not necessarily fragments.
Olivvv