diff --git a/lib/core/base/rule.js b/lib/core/base/rule.js index f12cdbd6..046a8189 100644 --- a/lib/core/base/rule.js +++ b/lib/core/base/rule.js @@ -310,11 +310,39 @@ Rule.prototype.run = function run(context, options = {}, resolve, reject) { if (options.performanceTimer) { this._logRulePerformance(); } - // Defer the rule's execution to prevent "unresponsive script" warnings. - // See https://github.com/dequelabs/axe-core/pull/1172 for discussion and details. - setTimeout(() => { + // [a11y-core]: runTypeASync ON resolves synchronously; OFF keeps the + // deferred setTimeout(0) resolve (Deque #1172) and records yield delay. + if (cache.get('runTypeASync')) { resolve(ruleResult); - }, 0); + } else { + let scheduledAt; + try { + scheduledAt = window.performance.now(); + } catch { + scheduledAt = undefined; + } + setTimeout(() => { + try { + if (scheduledAt !== undefined) { + const yieldDelay = window.performance.now() - scheduledAt; + const yieldStats = axe._typeASyncYield || { + totalMs: 0, + count: 0, + maxMs: 0 + }; + yieldStats.totalMs += yieldDelay; + yieldStats.count += 1; + if (yieldDelay > yieldStats.maxMs) { + yieldStats.maxMs = yieldDelay; + } + axe._typeASyncYield = yieldStats; + } + } catch { + // ignore instrumentation failures + } + resolve(ruleResult); + }, 0); + } }).catch(error => { if (options.performanceTimer) { this._logRulePerformance();