Refining clearTimeout behavior in IE

I have the following code:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title></title> </head> <body> <div id="logger"></div> <script> function log(txt) { document.getElementById('logger').innerHTML += txt + '<br>'; } var int = 10; var a= setTimeout(function(){ a = null; log("A fired!"); clearTimeout(b); b = null; }, int); var b = setTimeout(function(){ b = null; log("B fired!"); clearTimeout(a); a = null; }, int); </script> </body> </html> 

Both time callbacks should interfere with the other. In Opera, FF, and Chrome, only the first is executed (which prints "A fired"). But when I run the same code in IE6 and IE8, both callbacks are executed. Is this some kind of error in my scriupt or is it one of those errors that these browsers are full of? Does clearTimeout () / clearInterval () guarantee that the callback will not be called after they are called?

+4
source share
2 answers

I think what happens:

  • JavaScript has an event queue.
  • IE handles timeouts and queues two events.
  • The first timeout event is processed, and clearTimeout is called for B. However, the event for B is already queued, so it still fires.
  • the second timeout event is processed, and clearTimeout is called for A.

I suspect that in IE the event is queued and calling clearTimeout does not remove the event from the event queue.

It is also possible that there is simply a fake way in which IE pushes simultaneous timeouts into the queue ... The root cause can be diagnosed using two different timeouts, using 100% of the processor cycles for x time, and also by queues / (maybe it can insert events into the queue using window.postMessage () and catch them using window.onMessage ()).

I modified your existing code to better show the problem. It queues log items, rather than doing them immediately, because calling display () can cause layout or rendering, which can easily introduce other funky clutter.

Edit: you can test this using http://jsbin.com/ucukez/2 - if the browser has an error, then you get "A timeout fired" and msgstr "in standby mode".

Edit: this was fixed in IE9 - I could not reproduce in IE9 / IE10 / IE11.

HTML:

 <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>setTimeout queued test</title> <script> function display(txt) { document.getElementById('logger').innerHTML += txt + '<br>'; } var log = { items: [], push: function(text) { this.items.push(text); }, display: function() { var items = this.items; this.items = []; for (var i = 0; i < items.length; i++) { display(items[i]); } } }; function startTest() { var ms = 10; display("startTest()"); log.push('before A setTimeout'); var a = setTimeout(function(){ log.push('in A timeout fired'); display("A fired!"); log.push('in A clear timer B'); clearTimeout(b); log.push('in A cleared timer B'); }, ms); log.push('after A setTimeout'); log.push('before B setTimeout'); var b = setTimeout(function(){ log.push('in B timeout fired'); display("B fired!"); log.push('in B clear timer A'); clearTimeout(a); log.push('in B cleared timer A'); }, ms); log.push('after B setTimeout'); setTimeout(function(){ display(""); display("Displaying logged items:"); log.display(); },1000); } </script> </head> <body onload="startTest()"> <div id="logger"></div> </body> </html> 
+3
source

You set timeouts at the same time, and since they are both forked, you get inconsistent results

It is best to check the first timeout to see if the timeout really works as follows:

 var int = 10; var a= setTimeout(function(){ if (!a) return; a = null; log("A fired!"); clearTimeout(b); b = null; }, int); var b = setTimeout(function(){ if (!b) return; b = null; log("B fired!"); clearTimeout(a); a = null; }, int); 
0
source

All Articles