According to this StackOverflow question
Changing the DOM is synchronous. Rendering the DOM actually happens after the JavaScript stack has cleared.
and according to this google doc the screen fresh rate 60fps is equivalent to roughly refreshing every 16ms, I write this example:
<!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>
with jsfiddle link
I played around with the code and found that blocking happens with time delay under 12ms, and happens more often with lesser delay.
I have two different ways of comprehension:
In this case only
setTimeout
with time delay over 16ms should not block, time delay of 0 and 1 are way less than 16ms so both of them should block;Right after
setTimeout
call andlong
pushed to message queue (with optional delay), now the call stack is empty so in both casessetTimeout
should not block and 'calculating...' always be rendered.
What's wrong with my understanding?