Bug 1456843 - Compute FormLike elements lazily on <form>-less fields. r?MattN draft
authorMike Conley <mconley@mozilla.com>
Fri, 13 Jul 2018 12:41:06 -0400
changeset 817885 ecd8403fc696e9aac46b8c7fdd353e8aeec19ea7
parent 817669 e951f4ad123aa87d1d392c286db14cabb41a8560
push id116204
push usermconley@mozilla.com
push dateFri, 13 Jul 2018 16:45:18 +0000
reviewersMattN
bugs1456843
milestone63.0a1
Bug 1456843 - Compute FormLike elements lazily on <form>-less fields. r?MattN MozReview-Commit-ID: 3blElMxkejf
toolkit/modules/FormLikeFactory.jsm
--- a/toolkit/modules/FormLikeFactory.jsm
+++ b/toolkit/modules/FormLikeFactory.jsm
@@ -1,16 +1,18 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 var EXPORTED_SYMBOLS = ["FormLikeFactory"];
 
+ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
+
 /**
  * A factory to generate FormLike objects that represent a set of related fields
  * which aren't necessarily marked up with a <form> element. FormLike's emulate
  * the properties of an HTMLFormElement which are relevant to form tasks.
  */
 let FormLikeFactory = {
   _propsFromForm: [
     "action",
@@ -68,32 +70,42 @@ let FormLikeFactory = {
     }
 
     let rootElement = this.findRootForField(aField);
     if (ChromeUtils.getClassName(rootElement) === "HTMLFormElement") {
       return this.createFromForm(rootElement);
     }
 
     let doc = aField.ownerDocument;
-    let elements = [];
-    for (let el of rootElement.querySelectorAll("input, select")) {
-      // Exclude elements inside the rootElement that are already in a <form> as
-      // they will be handled by their own FormLike.
-      if (!el.form) {
-        elements.push(el);
-      }
-    }
+
     let formLike = {
       action: doc.baseURI,
       autocomplete: "on",
-      elements,
       ownerDocument: doc,
       rootElement,
     };
 
+    // FormLikes can be created when fields are inserted into the DOM. When
+    // many, many fields are inserted one after the other, we create many
+    // FormLikes, and computing the elements list becomes more and more
+    // expensive. Making the elements list lazy means that it'll only
+    // be computed when it's eventually needed (if ever).
+    XPCOMUtils.defineLazyGetter(formLike, "elements", function() {
+      let elements = [];
+      for (let el of this.rootElement.querySelectorAll("input, select")) {
+        // Exclude elements inside the rootElement that are already in a <form> as
+        // they will be handled by their own FormLike.
+        if (!el.form) {
+          elements.push(el);
+        }
+      }
+
+      return elements;
+    });
+
     this._addToJSONProperty(formLike);
     return formLike;
   },
 
   /**
    * Determine the Element that encapsulates the related fields. For example, if
    * a page contains a login form and a checkout form which are "submitted"
    * separately, and the username field is passed in, ideally this would return