Skip to content

Commit

Permalink
fix(perf): memoize axe.utils.select
Browse files Browse the repository at this point in the history
  • Loading branch information
dylanb committed Feb 4, 2018
1 parent 3274919 commit c9cd122
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 11 deletions.
2 changes: 2 additions & 0 deletions lib/core/base/audit.js
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ Audit.prototype.run = function (context, options, resolve, reject) {
this.validateOptions(options);

axe._tree = axe.utils.getFlattenedTree(document.documentElement); //cache the flattened tree
axe._selectCache = [];
var q = axe.utils.queue();
this.rules.forEach(function (rule) {
if (axe.utils.ruleShouldRun(rule, context, options)) {
Expand Down Expand Up @@ -180,6 +181,7 @@ Audit.prototype.run = function (context, options, resolve, reject) {
});
q.then(function (results) {
axe._tree = undefined; // empty the tree
axe._selectCache = undefined; // remove the cache
resolve(results.filter(function (result) { return !!result; }));
}).catch(reject);
};
Expand Down
38 changes: 27 additions & 11 deletions lib/core/utils/select.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,16 +45,10 @@ function isNodeInContext(node, context) {
* @param {Array} nodes The list of nodes to push
* @param {Object} context The "resolved" context object, @see resolveContext
*/
function pushNode(result, nodes, context) {
function pushNode(result, nodes) {
'use strict';

var temp;
var curried = (function (context) {
return function (node) {
return isNodeInContext(node, context);
};
})(context);
nodes = nodes.filter(curried);

if (result.length === 0) {
return nodes;
Expand Down Expand Up @@ -96,23 +90,45 @@ function hasOverlappingIncludes(includes) {
* @return {Array} Matching virtual DOM nodes sorted by DOM order
*/
axe.utils.select = function select(selector, context) {
//jshint maxstatements:20
'use strict';

var result = [], candidate;
if (!Array.isArray(context.include)) {
context.include = Array.from(context.include);
}
context.include.sort(axe.utils.nodeSorter); // ensure that the order of the include nodes is document order
for (var i = 0, l = context.include.length; i < l; i++) {
if (axe._selectCache) { // if used outside of run, it will still work
for (var j = 0, l = axe._selectCache.length; j < l; j++) {
// First see whether the item exists in the cache
let item = axe._selectCache[j];
if (item.selector === selector) {
return item.result;
}
}
}
var curried = (function (context) {
return function (node) {
return isNodeInContext(node, context);
};
})(context);
for (var i = 0; i < context.include.length; i++) {
candidate = context.include[i];
if (candidate.actualNode.nodeType === candidate.actualNode.ELEMENT_NODE &&
axe.utils.matchesSelector(candidate.actualNode, selector)) {
result = pushNode(result, [candidate], context);
axe.utils.matchesSelector(candidate.actualNode, selector) &&
curried(candidate)) {
result = pushNode(result, [candidate]);
}
result = pushNode(result, axe.utils.querySelectorAll(candidate, selector), context);
result = pushNode(result, axe.utils.querySelectorAllFilter(candidate, selector, curried));
}
if (context.include.length > 1 && hasOverlappingIncludes(context.include)) {
result.sort(axe.utils.nodeSorter);
}
if (axe._selectCache) {
axe._selectCache.push({
selector: selector,
result: result
});
}
return result;
};
49 changes: 49 additions & 0 deletions test/core/base/audit.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ describe('Audit', function () {
afterEach(function () {
fixture.innerHTML = '';
axe._tree = undefined;
axe._selectCache = undefined;
axe.utils.getFlattenedTree = getFlattenedTree;
});

Expand Down Expand Up @@ -479,6 +480,54 @@ describe('Audit', function () {
rules: {}
}, function () {
assert.isTrue(called);
axe.utils.getFlattenedTree = getFlattenedTree;
done();
}, isNotCalled);
});
it('should assign the result of getFlattenedTree to axe._tree', function (done) {
var thing = 'honey badger';
var saved = axe.utils.ruleShouldRun;
axe.utils.ruleShouldRun = function () {
assert.equal(axe._tree, thing);
return false;
};
axe.utils.getFlattenedTree = function () {
return thing;
};
a.run({ include: [document] }, {}, function () {
axe.utils.ruleShouldRun = saved;
done();
}, isNotCalled);
});
it('should clear axe._tree', function (done) {
var thing = 'honey badger';
axe.utils.getFlattenedTree = function () {
return thing;
};
a.run({ include: [document] }, {
rules: {}
}, function () {
assert.isTrue(typeof axe._tree === 'undefined');
axe.utils.getFlattenedTree = getFlattenedTree;
done();
}, isNotCalled);
});
it('should assign an empty array to axe._selectCache', function (done) {
var saved = axe.utils.ruleShouldRun;
axe.utils.ruleShouldRun = function () {
assert.equal(axe._selectCache.length, 0);
return false;
};
a.run({ include: [document] }, {}, function () {
axe.utils.ruleShouldRun = saved;
done();
}, isNotCalled);
});
it('should clear axe._selectCache', function (done) {
a.run({ include: [document] }, {
rules: {}
}, function () {
assert.isTrue(typeof axe._selectCache === 'undefined');
done();
}, isNotCalled);
});
Expand Down
12 changes: 12 additions & 0 deletions test/core/utils/select.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ describe('axe.utils.select', function () {

afterEach(function () {
fixture.innerHTML = '';
axe._selectCache = undefined;
});


Expand Down Expand Up @@ -148,6 +149,17 @@ describe('axe.utils.select', function () {
assert.equal(result.length, 3);

});
it ('should return the cached result if one exists', function () {
fixture.innerHTML = '<div id="zero"><div id="one"><div id="target1" class="bananas"></div></div>' +
'<div id="two"><div id="target2" class="bananas"></div></div></div>';

axe._selectCache = [{
selector: '.bananas',
result: 'fruit bat'
}];
var result = axe.utils.select('.bananas', { include: [axe.utils.getFlattenedTree($id('zero'))[0]] });
assert.equal(result, 'fruit bat');

});

});

0 comments on commit c9cd122

Please sign in to comment.