소스 검색

LibWeb: Let HTMLCollection cache its element list

Use the new DOM tree version mechanism to allow HTMLCollection to
remember its internal list of elements instead of rebuilding it on
every access.

This avoids thousands of full DOM walks while loading our GitHub repo.

~15% speed-up on jQuery subtests in Speedometer 3.0 :^)
Andreas Kling 1 년 전
부모
커밋
6bb4a2bfaa
2개의 변경된 파일26개의 추가작업 그리고 13개의 파일을 삭제
  1. 23 13
      Userland/Libraries/LibWeb/DOM/HTMLCollection.cpp
  2. 3 0
      Userland/Libraries/LibWeb/DOM/HTMLCollection.h

+ 23 - 13
Userland/Libraries/LibWeb/DOM/HTMLCollection.cpp

@@ -6,6 +6,7 @@
  */
 
 #include <LibWeb/Bindings/Intrinsics.h>
+#include <LibWeb/DOM/Document.h>
 #include <LibWeb/DOM/Element.h>
 #include <LibWeb/DOM/HTMLCollection.h>
 #include <LibWeb/DOM/ParentNode.h>
@@ -45,24 +46,33 @@ void HTMLCollection::visit_edges(Cell::Visitor& visitor)
 {
     Base::visit_edges(visitor);
     visitor.visit(m_root);
+    for (auto& element : m_cached_elements)
+        visitor.visit(element);
 }
 
 JS::MarkedVector<Element*> HTMLCollection::collect_matching_elements() const
 {
-    JS::MarkedVector<Element*> elements(m_root->heap());
-    if (m_scope == Scope::Descendants) {
-        m_root->for_each_in_subtree_of_type<Element>([&](auto& element) {
-            if (m_filter(element))
-                elements.append(const_cast<Element*>(&element));
-            return IterationDecision::Continue;
-        });
-    } else {
-        m_root->for_each_child_of_type<Element>([&](auto& element) {
-            if (m_filter(element))
-                elements.append(const_cast<Element*>(&element));
-            return IterationDecision::Continue;
-        });
+    if (m_cached_dom_tree_version != root()->document().dom_tree_version()) {
+        m_cached_elements.clear();
+        if (m_scope == Scope::Descendants) {
+            m_root->for_each_in_subtree_of_type<Element>([&](auto& element) {
+                if (m_filter(element))
+                    m_cached_elements.append(element);
+                return IterationDecision::Continue;
+            });
+        } else {
+            m_root->for_each_child_of_type<Element>([&](auto& element) {
+                if (m_filter(element))
+                    m_cached_elements.append(element);
+                return IterationDecision::Continue;
+            });
+        }
+        m_cached_dom_tree_version = root()->document().dom_tree_version();
     }
+
+    JS::MarkedVector<Element*> elements(heap());
+    for (auto& element : m_cached_elements)
+        elements.append(element);
     return elements;
 }
 

+ 3 - 0
Userland/Libraries/LibWeb/DOM/HTMLCollection.h

@@ -60,6 +60,9 @@ protected:
 private:
     virtual void visit_edges(Cell::Visitor&) override;
 
+    mutable u64 m_cached_dom_tree_version { 0 };
+    mutable Vector<JS::NonnullGCPtr<Element>> m_cached_elements;
+
     JS::NonnullGCPtr<ParentNode> m_root;
     Function<bool(Element const&)> m_filter;