2011-10-29 31 views
6

Benchmark比较QSA & .forEach VS一个NodeIterator当使用NodeIterator

toArray(document.querySelectorAll("div > a.klass")).forEach(function (node) { 
    // do something with node 
}); 

var filter = { 
    acceptNode: function (node) { 
     var condition = node.parentNode.tagName === "DIV" && 
      node.classList.contains("klass") && 
      node.tagName === "A"; 

     return condition ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT 
    } 
} 
// FIREFOX Y U SUCK 
var iter = document.createNodeIterator(document, NodeFilter.SHOW_ELEMENT, filter, false); 
var node; 
while (node = iter.nextNode()) { 
    // do thing with node  
} 

现在要么NodeIterator的吸或我做错了。

问题:什么时候应该使用NodeIterator

如果你不知道,DOM4指定什么NodeIterator是。

回答

9

由于各种原因,速度很慢。最明显的是没有人使用它,因此只需要很少的时间就可以优化它。另一个问题是它大量重入,每个节点都必须调用JS并运行过滤器函数。

如果你看看revision three of the benchmark,你会发现我已经使用getElementsByTagName("*")添加了迭代器的重做实例,然后在其上运行相同的过滤器。结果显示,它非常快速。去JS - > C++ - > JS很慢。

完全通过JS(getElementsByTagName)或C++(querySelectorAll)情况下完全过滤节点要比通过重复穿越边界快得多。

另请注意,querySelectorAll所使用的选择器匹配相对比较智能:它从左到右进行匹配,并基于预先计算的缓存(大多数浏览器将迭代所有元素的缓存列表, klass“,检查它是否为a元素,然后检查父代是否为div),因此它们甚至不会反复遍历整个文档。

鉴于此,何时使用NodeIterator?至少在JavaScript中基本上不会。在诸如Java之类的语言中(无疑是有一个名为NodeIterator的接口的主要原因),它可能与其他任何东西一样快,因为那时你的过滤器将与过滤器使用相同的语言。除此之外,唯一有意义的是在创建节点对象的内存使用量远远大于节点内部表示的语言中。