Since JavaScript is sequential (not counting async abilities), then why does it not "seem" to behave sequential as in this simplified example:
HTML:
<input type="button" value="Run" onclick="run()"/>
JS:
var btn = document.querySelector('input');
var run = function() {
console.clear();
console.log('Running...');
var then = Date.now();
btn.setAttribute('disabled', 'disabled');
// Button doesn't actually get disabled here!!????
var result = 0.0;
for (var i = 0; i < 1000000; i++) {
result = i * Math.random();
}
/*
* This intentionally long-running worthless for-loop
* runs for 600ms on my computer (just to exaggerate this issue),
* meanwhile the button is still not disabled
* (it actually has the active state on it still
* from when I originally clicked it,
* technically allowing the user to add other instances
* of this function call to the single-threaded JavaScript stack).
*/
btn.removeAttribute('disabled');
/*
* The button is enabled now,
* but it wasn't disabled for 600ms (99.99%+) of the time!
*/
console.log((Date.now() - then) + ' Milliseconds');
};
Finally, what would cause the disabled attribute not take effect until after the for-loop execution has happened? It's visually verifiable by simply commenting out the remove attribute line.
I should note that there is no need for a delayed callback, promise, or anything asynchronous; however, the only work around I found was to surround the for-loop and remaining lines in a zero delayed setTimeout callback which puts it in a new stack...but really?, setTimeout for something that should work essentially line-by-line?
What's really going on here and why isn't the setAttribute happening before the for loop runs?
The browser doesn't render changes to the DOM until the function returns. - @Barmar
Per @Barmar's comments and a lot of additional reading on the subject, I'll include a summary referring to my example:
Summarized another way is this quote from http://javascript.info/tutorial/events-and-timing-depth#javascript-execution-and-rendering
In most browsers, rendering and JavaScript use single event queue. It means that while JavaScript is running, no rendering occurs.
To explain it another way, I'll use the setTimeout "hack" I mentioned in my question:
Additional resources and explanations concerning the above: