Based on information from this StackOverflow post
The process of changing the DOM occurs synchronously, while rendering the DOM actually takes place after the JavaScript stack has cleared.
Furthermore, according to this document from Google, a screen refresh rate of 60fps is equivalent to refreshing every 16ms. In light of this, the following example code was created:
<!DOCTYPE html>
<html>
<head>
<script>
document.addEventListener('DOMContentLoaded', function() {
document.querySelector('#do').onclick = function() {
document.querySelector('#status').innerHTML = 'calculating...';
// setTimeout(long, 0); // will block
setTimeout(long, 1); // will not block
};
function long(){
let result = 0
for (let i = 0; i < 1000; i++) {
for (let j = 0; j < 1000; j++) {
for (let k = 0; k < 1000; k++) {
result += i + j + k;
}
}
}
document.querySelector('#status').innerHTML = 'calculation done';
document.querySelector('#result').innerHTML = result.toString();
}
});
</script>
</head>
<body>
<button id='do'> Do long calc!</button>
<div id='status'></div>
<div id='result'></div>
</body>
</html>
You can access the corresponding jsfiddle example via this link.
After experimenting with the code, it was observed that blocking occurs when the time delay is under 12ms, and happens more frequently with shorter delays.
There are two possible interpretations to consider:
In this scenario, only
setTimeout
with a time delay exceeding 16ms should not cause blocking, as both 0ms and 1ms delays are significantly less than 16ms;Immediately after calling
setTimeout
and addinglong
to the message queue (with an optional delay), the call stack is empty, therefore in both casessetTimeout
should not cause blocking and 'calculating...' should always be displayed.
If you spot any flaws in this understanding, please provide feedback.