From c03ef18a69cb1ba1b41870cffcbde1f00e8f52ea Mon Sep 17 00:00:00 2001 From: Utkarsh Chaudhary Date: Fri, 25 Apr 2025 21:44:13 +0530 Subject: [PATCH] Get selector optimisation --- lib/core/constants.js | 1 + lib/core/utils/get-selector.js | 18 +++++++++++++++--- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/lib/core/constants.js b/lib/core/constants.js index 3880c0a16..71918e37d 100644 --- a/lib/core/constants.js +++ b/lib/core/constants.js @@ -28,6 +28,7 @@ const definitions = [ const constants = { helpUrlBase: 'https://dequeuniversity.com/rules/', gridSize: 200, + selectorSimilarFilterLimit: 700, results: [], resultGroups: [], resultGroupMap: {}, diff --git a/lib/core/utils/get-selector.js b/lib/core/utils/get-selector.js index 17ffdb0ff..67b81438d 100644 --- a/lib/core/utils/get-selector.js +++ b/lib/core/utils/get-selector.js @@ -4,6 +4,8 @@ import getNodeAttributes from './get-node-attributes'; import matchesSelector from './element-matches'; import isXHTML from './is-xhtml'; import getShadowSelector from './get-shadow-selector'; +import memoize from './memoize'; +import constants from '../../core/constants'; const ignoredAttributes = [ 'class', @@ -376,8 +378,8 @@ function generateSelector(elm, options, doc) { } else { selector = features; } - if (!similar) { - similar = Array.from(doc.querySelectorAll(selector)); + if (!similar || similar.length > constants.selectorSimilarFilterLimit) { + similar = findSimilar(doc, selector); } else { similar = similar.filter(item => { return matchesSelector(item, selector); @@ -401,6 +403,16 @@ function generateSelector(elm, options, doc) { * @param {Object} optional options * @returns {String|Array} Unique CSS selector for the node */ -export default function getSelector(elm, options) { +function getSelector(elm, options) { return getShadowSelector(generateSelector, elm, options); } + +// Axe can call getSelector more than once for the same element because +// the same element can end up on multiple DqElements. +export default memoize(getSelector); + +// Similar elements create similar selectors. If there are lots of similar elements on the page, +// axe ends up needing to run that same selector many times. We can memoize for a huge perf boost. +const findSimilar = memoize((doc, selector) => + Array.from(doc.querySelectorAll(selector)) +);