a.klass")).forEac-6ren">
gpt4 book ai didi

javascript - 何时使用 NodeIterator

转载 作者:数据小太阳 更新时间:2023-10-29 04:34:03 30 4
gpt4 key购买 nike

Benchmark比较 QSA & .forEach对比 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是。

最佳答案

NodeIterator (和 TreeWalker ,就此而言)由于各种原因几乎从未使用过。这意味着有关该主题的信息很少,并且 answers like @gsnedders'来,这完全不合时宜。我知道这个问题已经有将近十年的历史了,所以请原谅我的死灵术。

1. 启动与表现

确实,启动NodeIteratorquerySelectorAll 之类的方法慢,但这不是您应该衡量的性能。

关于NodeIterator的事情s 是他们以这种方式生活,就像 HTMLCollection或直播 NodeList ,您可以在启动一次后继续使用该对象。NodeList返回者 querySelectorAll是静态的,每次需要匹配新添加的元素时都必须重新启动。

This version jsPerf 的 NodeIterator在准备代码中。实际测试仅尝试使用 iter.nextNode() 遍历所有新添加的元素。 .您可以看到迭代器现在快了几个数量级。

2. 选择器性能

好吧,爽。缓存迭代器更快。 This version然而,显示了另一个显着差异。我添加了 10 个选择器不应该匹配的类( done[0-9] )。迭代器丢失了大约 10% 它的速度,而 querySelectors 失去了 20% .

另一方面,this version , 显示添加另一个 div > 时发生的情况在选择器的开头。迭代器丢失 33% 它的速度,而 querySelectors 的速度是 增加 10% .

删除初始 div >在选择器的开头,如 this version表明这两种方法都变慢了,因为它们比早期版本匹配得更多。与预期的一样,在这种情况下,迭代器的性能相对比 querySelectors 更高。

这意味着在 NodeIterator 中基于节点自己的属性(它的类、属性等)进行过滤可能会更快。 ,虽然在选择器中有很多组合符(>、+、~ 等)可能意味着 querySelectorAll速度更快。对于 尤其如此。 (空间)组合器。使用 querySelectorAll('article a') 选择元素比手动循环遍历每个 a 的所有父级要容易得多元素,寻找具有 tagName 的元素的 'ARTICLE' .

附言在第 3.2 节中,我举了一个例子,说明如果您想要与空间组合器所做的相反的事情(排除带有 a 祖先的 article 标签),完全相反的情况如何成立。

3 不可能的选择器

3.1 简单的层次关系

当然,手动过滤元素为您提供了几乎无限的控制。这意味着您可以过滤掉通常无法与 CSS 选择器匹配的元素。例如,CSS 选择器只能以选择 div 的方式“回顾”。 s 前面是另一个 div可以使用 div + div .选择 div s 后跟另一个 div是不可能的。

然而,在 NodeFilter 里面,您可以通过检查 node.nextElementSibling.tagName === 'DIV' 来实现此目的.对于 CSS 选择器无法做出的每个选择,也是如此。

3.2 更全局的层级关系

我个人喜欢的另一件事 NodeIterator s,是您可以通过返回 NodeFilter.FILTER_REJECT 来拒绝一个节点及其整个子树。而不是 NodeFilter.FILTER_SKIP .

想象一下你想遍历所有 a页面上的标签,带有 article 的标签除外祖先。使用 querySelectors,您可以输入类似的内容

let a = document.querySelectorAll('a')
a = Array.prototype.filter.call(a, function (node) {
while (node = node.parentElement) if (node.tagName === 'ARTICLE') return false
return true
})

而在 NodeFilter ,你只需要输入这个
return node.tagName === 'ARTICLE' ? NodeFilter.FILTER_REJECT : // ✨ Magic happens here ✨
node.tagName === 'A' ? NodeFilter.FILTER_ACCEPT :
NodeFilter.FILTER_SKIP

综上所述

每次需要迭代相同类型的节点时,您不必启动 API。可悲的是,这个假设是在提出问题时做出的,+500 的答案(给予它更多的信任)甚至没有解决错误或任何好处 NodeIterator有。

有两大优势 NodeIterator必须提供:
  • 活力,如 §1
  • 中所述
  • 高级过滤,如第 3 节所述
    (我再怎么强调 NodeFilter.FILTER_REJECT 示例的用处都不为过)

  • 但是,不要使用 NodeIterator s 当以下任一情况为真时:
  • 它的实例只会被使用一次/几次
  • 使用 CSS 选择器可以查询复杂的层次关系
    (即 body.mobile article > div > div a[href^="/"])

  • 对不起,答案很长:)

    关于javascript - 何时使用 NodeIterator,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7941288/

    30 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com