Why do JS modal message windows pause the countdown on setTimeout ()?

I came across the unexpected behavior of JS setTimeout when modal dialogs like alert are open, and I would like to know the reason for this.

I expected setTimeout (fn, 10000) to mean “periodically check the current time, and when it is longer than + 10000 ms now, an event handler that will call the passed function“ fn ”. That would be logical if we now skipped the timeout value is “ms.” But apparently the countdown to setTimeout is a literal countdown and will be paused while the modal window is open.

 setTimeout(function(){ //alert A alert("10 seconds have passed for the first setTimeout") }, 10000); setTimeout(function(){ //alert B alert("Wait for 15 seconds and press OK"); },1000); 

I expect warning A to be displayed immediately after warning B closes (suppose you waited 15 seconds for this), since the warning timeout was only 10 seconds, and they have already passed. Practice, however, shows that the countdown to warning A simply pauses while warning B is open, and it will only be displayed after approx. Another 9 seconds elapsed after you closed warning B, no matter how long B was open.

This does not seem logical.

Update. I'm definitely not the only one getting confused here because this timeout suspension behavior occurs in Chrome and Internet Explorer, but not in Firefox. Firefox performs the behavior that I expected - if you wait 15 seconds for notification B - warning A pops up instantly when you close it.

+5
source share
3 answers

I doubt that there is a definitive answer about why IE and Chrome pause pending timers until alert is fired and Firefox doesn't. I believe this only because there is some freedom in interpreting the W3C specifications for alert :

The alert (message) method, when called, must perform the following steps:

  • If the nesting level of the completion of the event loop is nonzero, do not necessarily abort these steps.

  • Release the storage mutexes.

  • Show this message to the user.

  • If desired, pauses, waiting for the user to confirm the message.

Step 4 (pause) is further explained here :

Some of the algorithms in this specification, for historical reasons, require the user agent to pause during the execution of a task until the condition target is met. This means the following steps:

  • If any asynchronous algorithms are waiting for a stable state, then start their synchronous section, and then resume the asynchronous algorithm. (See the event loop model definition above for details.)

  • If necessary, update the visualization or user interface of any document or viewing context to reflect the current state.

  • Wait until the goal is reached. Although the user agent has suspended the task, the corresponding event loop should not trigger additional tasks, and any script in the current task should be blocked. User agents should however, despite the suspension, they remain sensitive to user input, albeit at a reduced capacity, since the event loop will do nothing.

Thus, the event loop is paused anyway. A longer timeout callback is not activated while the warning is still visible and modal. If not, all sorts of nasty things could become possible, like several warnings against each other.

Now, can you tell us about the above specifications, should you pause the timer for the duration of the warning, or is it better to fire it as soon as the warning appears? I can’t, and I'm not even sure which behavior would be more logical.

I am sure that you should not use JavaScript warnings for anything other than debugging. Alerts allow you to pause script execution (while some asynchronous operations, such as XHR, occur in the background), but they are rather unfriendly to the user. The right approach will cover asynchronous code using promises and possibly ES6 / yeild (if you are after the linear code style).

The following question is strongly related and some alternatives to alert are discussed there:

+5
source

alert is a user interface lock, and since Javascript is single, it blocks anything from starting until the dialog is rejected.

-1
source

If you really need to, you can use your own timer.

 var now = Date.now(); function alertA(){ //alert A alert("10 seconds have passed for the first setTimeout") } setTimeout(function(){ //alert B alert("Wait for 15 seconds and press OK"); setTimeout(alertA, 10000 - (Date.now() - now)); // Subtract the time passed },1000); 

You can wrap this with a utility method:

 function alertDelay(messages, timePassed) { if (typeof messages !== "object" || messages.length === 0) return; if (timePassed == null) timePassed = 0; var firstMessage = messages[0]; var now = Date.now(); setTimeout(function() { alert(firstMessage.message); alertDelay(messages.slice(1), Date.now() - now); }, firstMessage.delay - timePassed); } 

Using:

 alertDelay([ {message: 'Message 1', delay: 1000}, {message: 'Message 2', delay: 5000}, {message: 'Message 3', delay: 10000} ]); 
-1
source

Source: https://habr.com/ru/post/1205180/


All Articles