开发者

Context-based getElementById is 1000 time slower than native getElementById. Do selector engines like sizzle use a cleverer strategy?

Being interested in building html chunks off-dom before to insert them in the dom, I have done some testing using dynatrace. I used b开发者_开发问答obince's method : Is there any way to find an element in a documentFragment?

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 ?


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.


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜