Say I have a class in JavaScript (yes bad bad class, bad class in JS, but its for web components, one has to use classes).
I would like to create a cached attribute getter for elements on a class, in python it would be this:
class Foo(object):
_elements = {}
def __getattr__(self, name):
if name in ['widget1', 'widget2', 'widget3']: # A long list of items, don't want to create getters for each one individiually
if not _elements.get(name):
self._elements[name] = self.getElementById(name)
return self._elements[name]
else:
# Default behaviour
return object.__getattr__(self, name)
This is the closest I got, but its ugly to use:
this.el['widget1']
this.widget1
class Foo extends HTMLElement {
el(id) {
// Cached get element by id
this._els = this._els || {};
if (!this._els[id]) {
this._els[id] = this.getElementById(id)
}
return this._els[id]
}
getElementById
is slower
But does your cached performance gain outway extra code, code complexity and time coding?
1 PICO second equals 0.00000001 Milliseconds
<div style="display:grid;grid-template-columns:1fr 1fr">
<test-component id="CACHED"></test-component>
<test-component id="BYID"></test-component>
</div>
<div id="DIFF"><b>100.000 calls per run:</b></div>
<script>
customElements.define("test-component", class extends HTMLElement {
el(id) {
this._els = this._els || {};
if (!this._els[id]) this._els[id] = document.getElementById(id);
return this._els[id]
}
get CACHED() {
return this.el("CACHED");
}
get BYID() {
return document.getElementById("BYID");
}
connectedCallback() {
let count = 100000;
for (let run = 1; run < 9; run++) {
let log = [];
for (let cnt = 0; cnt < count; cnt++) {
const t0 = performance.now();
this == CACHED ? this.CACHED : this.BYID;// test performance
log.push(performance.now() - t0);
}
this.average = (log.reduce((a, b) => a + b) / log.length)*1e9;
let diff = (BYID.average - CACHED.average).toPrecision(2);
if (this == BYID) DIFF.innerHTML += `<div>Run #${run} = <b>${diff/count}</b> PICO seconds slower per call<div>`;
}
}
})
</script>