I often run a conditional to make sure a value has changed before updating the DOM, ex:
const startSize = 10
function updateAttribute(newSize){
if (newSize === startSize) return
document.body.setAttribute('data-size', newSize)
}
function updateStyle(newSize){
if (newSize === startSize) return
document.body.style.setProperty('--my-size', newSize)
}
Is this an over-optimization? Does the browser already run this check and only apply the new value if it's different from the old?
Setting an element's attribute almost always have (observable) side effects. And these side effects must kick in even when they're set to their current value.
This is highly visible for instance with the <canvas>
element, where setting either its width
or height
will reset its buffer.
const canvas = document.querySelector("canvas");
canvas.getContext("2d").fillRect(50, 50, 80, 80);
setTimeout(() => {
canvas.setAttribute("width", canvas.getAttribute("width"));
}, 3000);
<canvas></canvas>
But also with media elements where setting their src
or alike attributes will load the resource again, possibly triggering a full re-fetch if the resource isn't cached:
const img = document.querySelector("img");
setTimeout(() => {
img.setAttribute("src", img.getAttribute("src"));
}, 3000);
<img src=https://upload.wikimedia.org/wikipedia/commons/2/2c/Rotating_earth_%28large%29.gif >
And even with data- attributes, where we could have thought there wouldn't be any side effects, this is still observable and browsers can't really optimize it out:
const el = document.querySelector("div");
setTimeout(() => {
el.setAttribute("data-foo", el.getAttribute("data-foo"));
}, 3000);
const observer = new MutationObserver((recs) => recs.forEach((r) => console.log("attribute %s did change", r.attributeName)));
observer.observe(el, { attributes: true });
<div data-foo="bar"></div>
Now, each attribute's side effect will have different cost, so it's up to you to determine if that cost is worth the check or not (e.g, in my <canvas>
it's definitely worth it, but in your data- attribute case, it's less obvious, if you don't have an active observer you can almost ignore it.
Regarding the CSSOM, the browser will most likely optimize it.
Apart from through your browser's dev-tools a "no-change update" isn't really observable there. So your .style.setProperty()
case corresponds to a simple data- attribute change.