mirror of
https://github.com/priyanshujain/sanderling.git
synced 2026-10-02 19:17:10 +00:00
perf(web-runtime): cache randomTap candidate DOM scan per tick
The 16-attempt retry loop in __sanderlingNextAction__ called randomTap repeatedly; each call ran querySelectorAll over a-button- input-... and re-flushed layout per match via getBoundingClientRect. On heavy SPA routes that's the per-tick budget gone. Cache the scan in a module-level slot, reset at the top of each __sanderlingNextAction__ invocation so the cache doesn't outlive a tick.
This commit is contained in:
1 parent
359527569f
commit
fc1e6f9319
1 file changed
+18
-9
@@ -434,16 +434,23 @@ function resolveGenerator(handle: ActionGeneratorHandle): unknown {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Per-tick cache so the 16-attempt retry loop in __sanderlingNextAction__
|
||||||
|
// doesn't re-walk the DOM and re-flush layout on every iteration.
|
||||||
|
let randomTapCandidates: HTMLElement[] | null = null;
|
||||||
|
|
||||||
function randomTap(): unknown {
|
function randomTap(): unknown {
|
||||||
const candidates = Array.from(
|
if (!randomTapCandidates) {
|
||||||
document.querySelectorAll<HTMLElement>(
|
randomTapCandidates = Array.from(
|
||||||
'a, button, input, select, textarea, [role="button"], [onclick]',
|
document.querySelectorAll<HTMLElement>(
|
||||||
),
|
'a, button, input, select, textarea, [role="button"], [onclick]',
|
||||||
).filter((element) => {
|
),
|
||||||
if ((element as HTMLButtonElement).disabled) return false;
|
).filter((element) => {
|
||||||
const rect = element.getBoundingClientRect();
|
if ((element as HTMLButtonElement).disabled) return false;
|
||||||
return rect.width > 0 && rect.height > 0;
|
const rect = element.getBoundingClientRect();
|
||||||
});
|
return rect.width > 0 && rect.height > 0;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const candidates = randomTapCandidates;
|
||||||
if (candidates.length === 0) return null;
|
if (candidates.length === 0) return null;
|
||||||
const picked = candidates[Math.floor(Math.random() * candidates.length)];
|
const picked = candidates[Math.floor(Math.random() * candidates.length)];
|
||||||
if (!picked) return null;
|
if (!picked) return null;
|
||||||
@@ -542,6 +549,8 @@ defineLockedGlobal("__sanderlingExtractors__", function (): Record<number, unkno
|
|||||||
|
|
||||||
defineLockedGlobal("__sanderlingNextAction__", function (): unknown {
|
defineLockedGlobal("__sanderlingNextAction__", function (): unknown {
|
||||||
if (!actionsRoot) return null;
|
if (!actionsRoot) return null;
|
||||||
|
// Reset per-tick caches so each invocation gets a fresh DOM scan.
|
||||||
|
randomTapCandidates = null;
|
||||||
// Match the goja runtime: retry up to 16 times when a weighted entry's
|
// Match the goja runtime: retry up to 16 times when a weighted entry's
|
||||||
// generator returns []. Otherwise on routes where most generators are
|
// generator returns []. Otherwise on routes where most generators are
|
||||||
// gated to other pages, ~80% of ticks would emit no action.
|
// gated to other pages, ~80% of ticks would emit no action.
|
||||||
|
|||||||
Reference in new issue
Block a user