jenkins-bot has submitted this change and it was merged. ( https://gerrit.wikimedia.org/r/386009 )
Change subject: Remove unnecessary calls to Node#childNodes ...................................................................... Remove unnecessary calls to Node#childNodes These calls force us to allocate a backing array for childNodes, deoptimizing a linked list DOM representation. Iterate over the children using Node#firstChild / Node#nextSibling instead, which can be efficiently done w/o allocating a backing array. Change-Id: Ibed52d3d82a7fc54796d7ef6f1cf771a6f48b974 --- M lib/utils/DOMUtils.js M lib/wt2html/XMLSerializer.js M lib/wt2html/pp/processors/computeDSR.js M lib/wt2html/pp/processors/handlePres.js 4 files changed, 20 insertions(+), 30 deletions(-) Approvals: Subramanya Sastry: Looks good to me, approved Legoktm: Looks good to me, approved jenkins-bot: Verified diff --git a/lib/utils/DOMUtils.js b/lib/utils/DOMUtils.js index c9cd9fb..dc221ce 100644 --- a/lib/utils/DOMUtils.js +++ b/lib/utils/DOMUtils.js @@ -815,9 +815,8 @@ * Check whether a node has any children that are elements. */ hasElementChild: function(node) { - var children = node.childNodes; - for (var i = 0, n = children.length; i < n; i++) { - if (DU.isElt(children[i])) { + for (var child = node.firstChild; child; child = child.nextSibling) { + if (DU.isElt(child)) { return true; } } @@ -829,9 +828,7 @@ * Check if a node has a block-level element descendant. */ hasBlockElementDescendant: function(node) { - var children = node.childNodes; - for (var i = 0, n = children.length; i < n; i++) { - var child = children[i]; + for (var child = node.firstChild; child; child = child.nextSibling) { if (DU.isElt(child) && // Is a block-level node (this.isBlockNode(child) || @@ -997,15 +994,14 @@ switch (node.nodeType) { case node.ELEMENT_NODE: var nodeName = node.nodeName.toLowerCase(); - var children = node.childNodes; var attrInfo = domAttrsToTagAttrs(node.attributes); if (Util.isVoidElement(nodeName)) { tokBuf.push(new pd.SelfclosingTagTk(nodeName, attrInfo.attrs, attrInfo.dataAttrs)); } else { tokBuf.push(new pd.TagTk(nodeName, attrInfo.attrs, attrInfo.dataAttrs)); - for (var i = 0, n = children.length; i < n; i++) { - tokBuf = this.convertDOMtoTokens(tokBuf, children[i]); + for (var child = node.firstChild; child; child = child.nextSibling) { + tokBuf = this.convertDOMtoTokens(tokBuf, child); } var endTag = new pd.EndTagTk(nodeName); // Keep stx parity @@ -1966,15 +1962,16 @@ * See encapsulateExpansionHTML's doc. for more info about these options. */ buildDOMFragmentTokens: function(env, token, docOrHTML, addAttrsCB, opts) { - var body; + var body, nodes; if (docOrHTML.constructor === String) { body = DU.ppToDOM(docOrHTML); } else { body = docOrHTML.body; } - var nodes = body.childNodes; - if (nodes.length === 0) { + if (body.hasChildNodes()) { + nodes = body.childNodes; + } else { // RT extensions expanding to nothing. nodes = [body.ownerDocument.createElement('link')]; } diff --git a/lib/wt2html/XMLSerializer.js b/lib/wt2html/XMLSerializer.js index a1b1864..2c2a993 100644 --- a/lib/wt2html/XMLSerializer.js +++ b/lib/wt2html/XMLSerializer.js @@ -238,9 +238,8 @@ var accum = options.captureOffsets ? accumOffsets.bind(null, out) : function(bit) { out.str += bit; }; if (options.innerXML) { - var children = node.childNodes; - for (var i = 0; i < children.length; i++) { - serializeToString(children[i], options, accum); + for (var child = node.firstChild; child; child = child.nextSibling) { + serializeToString(child, options, accum); } } else { serializeToString(node, options, accum); diff --git a/lib/wt2html/pp/processors/computeDSR.js b/lib/wt2html/pp/processors/computeDSR.js index bbb4af2..716909f 100644 --- a/lib/wt2html/pp/processors/computeDSR.js +++ b/lib/wt2html/pp/processors/computeDSR.js @@ -173,9 +173,6 @@ }); } - var children = node.childNodes; - var numChildren = children.length; - // No undefined values here onwards. // NOTE: Never use !s, !e, !cs, !ce for testing for non-null // because any of them could be zero. @@ -187,7 +184,7 @@ e = null; } - if (e === null && numChildren === 0) { + if (e === null && !node.hasChildNodes()) { e = s; } @@ -204,7 +201,6 @@ var rtTestMode = env.conf.parsoid.rtTestMode; var child = node.lastChild; - var i = numChildren - 1; while (child !== null) { var prevChild = child.previousSibling; var isMarkerTag = false; @@ -244,6 +240,7 @@ } env.log("trace/dsr", function() { + var i = child.parentNode.childNodes.indexOf(child); // slow, for debugging only return " CHILD: <" + child.parentNode.nodeName + ":" + i + ">=" + (DU.isElt(child) ? '' : (DU.isText(child) ? '#' : '!')) + @@ -608,12 +605,10 @@ node.replaceChild(newNode, prevChild); node.removeChild(nextChild); prevChild = newNode.previousSibling; - i--; } node.removeChild(child); } - i--; child = prevChild; } diff --git a/lib/wt2html/pp/processors/handlePres.js b/lib/wt2html/pp/processors/handlePres.js index 64f67b1..d5668d5 100644 --- a/lib/wt2html/pp/processors/handlePres.js +++ b/lib/wt2html/pp/processors/handlePres.js @@ -12,14 +12,13 @@ } function reinsertLeadingSpace(elt, isLastChild) { - var children = elt.childNodes; - for (var i = 0, n = children.length; i < n; i++) { - var c = children[i]; + for (var c = elt.firstChild; c; c = c.nextSibling) { + var last = (c.nextSibling === null); if (DU.isText(c)) { - c.data = fixedIndentPreText(c.data, isLastChild && i === n - 1); + c.data = fixedIndentPreText(c.data, isLastChild && last); } else { // recurse - reinsertLeadingSpace(c, isLastChild && i === n - 1); + reinsertLeadingSpace(c, isLastChild && last); } } } @@ -85,11 +84,11 @@ } function findAndHandlePres(elt, indentPresHandled) { - var children = elt.childNodes; + var nextChild; var blocklevel = false; - for (var i = 0; i < children.length; i++) { + for (var n = elt.firstChild; n; n = nextChild) { var processed = false; - var n = children[i]; + nextChild = n.nextSibling; // store this before n is possibly deleted if (!indentPresHandled && DU.isElt(n) && Util.tagOpensBlockScope(n.nodeName) && (DU.isTplMetaType(n.getAttribute("typeof")) || -- To view, visit https://gerrit.wikimedia.org/r/386009 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: Ibed52d3d82a7fc54796d7ef6f1cf771a6f48b974 Gerrit-PatchSet: 5 Gerrit-Project: mediawiki/services/parsoid Gerrit-Branch: master Gerrit-Owner: C. Scott Ananian <canan...@wikimedia.org> Gerrit-Reviewer: Arlolra <abrea...@wikimedia.org> Gerrit-Reviewer: C. Scott Ananian <canan...@wikimedia.org> Gerrit-Reviewer: Legoktm <lego...@member.fsf.org> Gerrit-Reviewer: Sbailey <sbai...@wikimedia.org> Gerrit-Reviewer: Subramanya Sastry <ssas...@wikimedia.org> Gerrit-Reviewer: jenkins-bot <> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits