I'm studying browser rendering mechanics and want to be able to optimize different action handling on same event and understand what impacts repaints in these cases.
Here I try to change the style of a span (action 1) and just do something more expensive by incrementing a value in a loop (action 2)
I don't understand why span's style change is being delayed (most of the time, but not always too) if I put the second action in
setTimeout(with 0ms delay set)If
setTimeout's delay is set to 1ms it never blocks style change, why is there a difference for 0 and 1 here?If we remove
setTimeoutand keep all the logic in a promise chain it always blocks the span style change, does that mean that chained microtasks that work with synchronous code only are basically same as having a synchronous loop in this case. They are blocking repaints and cannot be used for such optimizations?
P.S. Maybe someone knows a good resource for studying this stuff, mostly optimizing script execution throughout different rendering frames?
document.addEventListener("click", (evt) => {
if (!evt.target.matches("span")) { return; }
evt.target.style.color = "red";
setTimeout(() => {
const loopTimes = 900000;
const result = Array(loopTimes)
.fill()
.reduce((acc, val, i) => {
return acc.then((val) => {
return val + 1;
});
}, Promise.resolve(0));
result.then((endResult) => console.log(endResult));
}, +evt.target.dataset.timeout);
});
<span data-timeout="0">click for red (0ms)</span><br>
<span data-timeout="1">click for red (1ms)</span>