【问题标题】:How does querySelector works under the hood? [closed]querySelector 如何在后台工作? [关闭]
【发布时间】:2014-11-01 03:47:32
【问题描述】:

每个人都知道像 document.getElementByID(...)document.querySelector(...) 这样的 DOM 选择器是做什么的,以及如何将它与类、属性、id 等一起使用。

但我无法找到它是如何工作的(我可以找到perf test comparisons,但我对理论很感兴趣)。我知道 html 页面已加载,由浏览器解析并构建了 DOM 树。但是每个选择器如何遍历 DOM 树来查找元素。

我查看了spec for parsing algorithm 并阅读了非常好的explanation how Browsers work,但它也对 HTML、CSS 解析和渲染流程给出了很好的解释,它没有解释每个选择器如何遍历这棵树来查找要素。

我假设为了找到像.blackspan 这样的东西,它需要遍历整个树,但是要找到#id,它可能会遍历一些额外的数据结构,从而使其更快。请不要写你的假设,我正在寻找具体的知识,并在某些浏览器中备份规范或实现。

【问题讨论】:

  • 我认为这个问题最好在programmers.stackexchange.com
  • 这是一个实现细节,会因您使用的引擎而异。如果你想知道,你必须阅读各种实现的源代码。以en.wikipedia.org/wiki/List_of_ECMAScript_engines 为起点。
  • 浏览器的工作方式只能由编写它们的人指定,并且每个人都可能不同。各种规范没有定义实现细节,只定义了它们必须如何工作。像 MDN 和 MSDN 这样的网站不会提供关于浏览器内部的启示。例如。我猜浏览器会创建一个 ID 索引以供 getElementById 使用,并且可能与流行的 CSS 选择器(如类和标记名)类似,但找到一个规范来定义这可能是一个挑战。跨度>
  • @salvadordali 同意......但你说的是“具体知识”,这只能通过阅读源代码获得。也许知道引擎实现的人会回复,但即便如此,您也只能获得关于一种实现的具体知识。
  • @SalvadorDali - 如果你想知道他们是如何“在幕后”做到这一点的,这里是为 Webkit 处理 DOM 的源代码:trac.webkit.org/browser/trunk/Source/WebCore/dom 和 Gecko:lxr.mozilla.org/mozilla/source/content/base/public

标签: javascript dom internals selectors-api


【解决方案1】:

检查 Firefox's source 并阅读 the related documentation 将有助于获得一些初步的见解。
获取文档后,将其传递给解析器(请参阅:/mozilla/parser/html/),解析器将仔细阅读文档并生成内容树。解析器的核心部分是用 Java (/mozilla/parser/html/javasrc/) 编写的,然后翻译成 C++ 进行构建,所以当您想阅读源代码的其余部分时,请准备好享受美好时光。

查看解析器的源码(/mozilla/parser/html/javasrc/TreeBuilder.java),即函数startTag的摘录:

1579         if (errorHandler != null) {
1580             // ID uniqueness
1581             @IdType String id = attributes.getId();
1582             if (id != null) {
1583                 LocatorImpl oldLoc = idLocations.get(id);
1584                 if (oldLoc != null) {
1585                     err("Duplicate ID \u201C" + id + "\u201D.");
1586                     errorHandler.warning(new SAXParseException(
1587                             "The first occurrence of ID \u201C" + id
1588                             + "\u201D was here.", oldLoc));
1589                 } else {
1590                     idLocations.put(id, new LocatorImpl(tokenizer));
1591                 }
1592             }
1593         }

将注意力转向第 1590 行,并记住在同一个文件的前面我们有:

459     private final Map<String, LocatorImpl> idLocations = new HashMap<String, LocatorImpl>();

我们可以看到节点 ID 保存在一个简单的哈希映射中。 查看类的处理方式是留给读者的练习。

不同的 DOM 方法,例如 document.getElementByID(...),通过胶水代码和大量对象层次结构连接到此哈希映射,请参阅 "How is the web-exposed DOM implemented?" on ask.mozilla.org

【讨论】:

  • 很好的答案!!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-01-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-07
相关资源
最近更新 更多