From a9bff13a1e2f710739ecef70dc6ae7bf17844652 Mon Sep 17 00:00:00 2001 From: Stephen Mathieson Date: Wed, 9 Jan 2019 10:16:36 -0500 Subject: [PATCH] feat: use `requestIdleCallback` when possible (#61) This patch builds on #59 (hat tip to @agreene-coursera!!) and uses `requestIdleCallback` rather than `setTimeout` in environments that support it. If the host environment does not support `requestIdleCallback`, a shim will be used (via [`npmjs.com/requestidlecallback`](https://www.npmjs.com/package/requestidlecallback)). Closes #59. --- index.js | 126 ++++++++++++++++++++++++---------------------- package-lock.json | 5 ++ package.json | 3 +- 3 files changed, 74 insertions(+), 60 deletions(-) diff --git a/index.js b/index.js index ae9e856..76656e6 100644 --- a/index.js +++ b/index.js @@ -1,6 +1,11 @@ /* global document, window, Promise */ var axeCore = require('axe-core'); +var rIC = require('requestidlecallback'); var after = require('./after'); + +var requestIdleCallback = rIC.request; +var cancelIdleCallback = rIC.cancel; + var React = undefined; var ReactDOM = undefined; @@ -11,7 +16,7 @@ var moderate = 'color:orange;font-weight:bold;'; var minor = 'color:orange;font-weight:normal;'; var defaultReset = 'font-color:black;font-weight:normal;'; -var timer; +var idleId; var timeout; var _createElement; var components = {}; @@ -108,75 +113,78 @@ function createDeferred() { } function checkAndReport(node, timeout) { - if (timer) { - clearTimeout(timer); - timer = undefined; + if (idleId) { + cancelIdleCallback(idleId); + idleId = undefined; } var deferred = createDeferred(); nodes.push(node); - timer = setTimeout(function() { - var n = getCommonParent(nodes); - if (n.nodeName.toLowerCase() === 'html') { - // if the only common parent is the body, then analyze the whole page - n = document; - } - axeCore.run(n, { reporter: 'v2' }, function(error, results) { - if (error) { - return deferred.reject(error); + idleId = requestIdleCallback( + function() { + var n = getCommonParent(nodes); + if (n.nodeName.toLowerCase() === 'html') { + // if the only common parent is the body, then analyze the whole page + n = document; } + axeCore.run(n, { reporter: 'v2' }, function(error, results) { + if (error) { + return deferred.reject(error); + } - results.violations = results.violations.filter(function(result) { - result.nodes = result.nodes.filter(function(node) { - var key = node.target.toString() + result.id; - var retVal = !cache[key]; - cache[key] = key; - return retVal; + results.violations = results.violations.filter(function(result) { + result.nodes = result.nodes.filter(function(node) { + var key = node.target.toString() + result.id; + var retVal = !cache[key]; + cache[key] = key; + return retVal; + }); + return !!result.nodes.length; }); - return !!result.nodes.length; - }); - if (results.violations.length) { - console.group('%cNew aXe issues', serious); - results.violations.forEach(function(result) { - var fmt; - switch (result.impact) { - case 'critical': - fmt = critical; - break; - case 'serious': - fmt = serious; - break; - case 'moderate': - fmt = moderate; - break; - case 'minor': - fmt = minor; - break; - default: - fmt = minor; - break; - } - console.groupCollapsed( - '%c%s: %c%s %s', - fmt, - result.impact, - defaultReset, - result.help, - result.helpUrl - ); - result.nodes.forEach(function(node) { - failureSummary(node, 'any'); - failureSummary(node, 'none'); + if (results.violations.length) { + console.group('%cNew aXe issues', serious); + results.violations.forEach(function(result) { + var fmt; + switch (result.impact) { + case 'critical': + fmt = critical; + break; + case 'serious': + fmt = serious; + break; + case 'moderate': + fmt = moderate; + break; + case 'minor': + fmt = minor; + break; + default: + fmt = minor; + break; + } + console.groupCollapsed( + '%c%s: %c%s %s', + fmt, + result.impact, + defaultReset, + result.help, + result.helpUrl + ); + result.nodes.forEach(function(node) { + failureSummary(node, 'any'); + failureSummary(node, 'none'); + }); + console.groupEnd(); }); console.groupEnd(); - }); - console.groupEnd(); - } + } - deferred.resolve(); - }); - }, timeout); + deferred.resolve(); + }); + }, + { timeout: timeout } + ); return deferred.promise; } diff --git a/package-lock.json b/package-lock.json index 791c5f8..52fe67f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4347,6 +4347,11 @@ "throttleit": "~0.0.2" } }, + "requestidlecallback": { + "version": "0.3.0", + "resolved": "https://agora.dequecloud.com/artifactory/api/npm/dequelabs/requestidlecallback/-/requestidlecallback-0.3.0.tgz", + "integrity": "sha1-b7dOBzP5DfP6pIOPn2oqX5t0KsU=" + }, "require-uncached": { "version": "1.0.3", "resolved": "https://agora.dequecloud.com/artifactory/api/npm/dequelabs/require-uncached/-/require-uncached-1.0.3.tgz", diff --git a/package.json b/package.json index 54e019f..17730e3 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,8 @@ "author": "Dylan Barrell (dylan@barrell.com)", "license": "MPL-2.0", "dependencies": { - "axe-core": "^3.0.0" + "axe-core": "^3.0.0", + "requestidlecallback": "^0.3.0" }, "devDependencies": { "cypress": "^3.0.3",