I have two elements, a paragraph and a button. On clicking the button, the browser should render the text "Waiting"
with the p
tag, wait 3 seconds and render the text "Done"
after. It runs but the text "Waiting"
is never rendered.
I know this can be solved with setTimeout
but I am trying to understand why the text "Waiting"
does not show up at all.
html:
<p id="p">Ready</p>
<button id="button">Start</button>
Javascript:
const pTag = document.getElementById('p');
const button = document.getElementById('button');
button.onclick = () => {
pTag.innerText = 'Waiting';
syncWaitSeconds(3)
pTag.innerText = 'Done';
};
function syncWaitSeconds(seconds = 3){
const start = Date.now();
const time = seconds * 1000
while (Date.now() - start <= time) {
// waiting 3 seconds
}
}
I am learning Javascript, I want to know why the text was not showing up. As changing the innerText does not return a promise and is synchronous, shouldn't it have happened first, then the wait for 3 seconds and finally the render of the text 'Done' ?
CodePudding user response:
It's because you are doing busy-wait, that is, your browser is too busy always comparing those dates and it simply does not get to update the UI. This is a good example for the need of asynchronity. It is not "just" the innerText
that's not refreshing, it's the whole UI being unresponsive while this busy-wait happens.
This is why you need to do this asynchronously via setTimeout
. Without setTimeout
:
const pTag = document.getElementById('p');
const button = document.getElementById('button');
button.onclick = () => {
pTag.innerText = 'Waiting';
syncWaitSeconds(3)
pTag.innerText = 'Done';
};
function syncWaitSeconds(seconds = 3){
const start = Date.now();
const time = seconds * 1000
while (Date.now() - start <= time) {
// waiting 3 seconds
}
}
<p id="p"></p>
<button id="button">My Button</button>
With setTimeout
:
const pTag = document.getElementById('p');
const button = document.getElementById('button');
button.onclick = () => {
pTag.innerText = 'Waiting';
setTimeout(function() {
pTag.innerText = 'Done';
}, 3000);
};
<p id="p"></p>
<button id="button">My Button</button>