DOM cache API
The DOM cache API can be used to save computations on DOM nodes (e.g. elements). Values are cached per node.
For example, testing if an element is part of the accessibility tree includes multiples tests not only on the node itself but also all of the ancestors, for instance:
- Does the element or one of its ancestors have the
hiddenattribute? - Does the element or one of its ancestors have the
inertattribute? - Does the element or one of its ancestors have
aria-hidden="true"? - etc
Testing if an element is part of the accessibility tree is a frequent test required by most of the a11y related tests and thus gains by caching the result.
WARNING
The cache API is only available after the DOM is fully constructed, i.e. after the dom:ready event has fired.
When to use
There is no definitive answer as it is always a tradeof between memory and performance but as a rule of thumb you should use the cache API if the computation result:
- Is reused in multiple rules.
- Is reused multiple times within the same rule.
- Involves ancestors or descendants (cache the intermediate result on each node as you go)
Cache key
Each cache must use a unique key.
The cache is stored per DOMNode so the key must only be unique per type of computation not per instance.
The cache key is typically Symbol named after the function performing the calculation but any unique string can be used.
const CACHE_KEY = Symbol(myFunction.name);
function myFunction(): void {
/* ... */
}
Type safety (typescript)
Type safety can be archived by augmenting the DOMNodeCache interface:
declare module "html-validate" {
export interface DOMNodeCache {
[CACHE_KEY]?: number;
}
}
This ensures the typescript type system will correctly infer the proper datatypes when storing and fetching values.
Type declaration is optional but strongly recommended.
Without type declaration the value is implied to be any and the user must manually ensure it is of the correct type.
Example
const CACHE_KEY = Symbol(myFunction.name);
declare module "html-validate" {
export interface DOMNodeCache {
[CACHE_KEY]: number;
}
}
export function myFunction(node: HtmlElement): number {
const cached = node.cacheGet(CACHE_KEY);
if (typeof cached !== "undefined") {
return cached;
}
const value = expensiveComputation(node);
return node.cacheSet(CACHE_KEY, value);
}
API
DOMNode.cacheGet<K>(key: K): DOMNodeCache[K] | undefined
Fetch cached value from a DOMNode.
Returns undefined if no cached value is present.
DOMNode.cacheSet<K>(key: K, value: DOMNodeCache[K]): DOMNodeCache[K]
Store value on DOMNode.
DOMNode.cacheRemove<K>(key: K): boolean
Remove value from DOMNode.
Returns true if a value was present and false if there was none.
DOMNode.cacheExists<K>(key: K): boolean
Check if a value is cached in DOMNode.