在IE

2011-05-02 91 views
4

洁肤clearTimeout行为我有以下代码:在IE

<!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> 

两个超时回调应防止发射另一个另一个。在Opera中,FF和Chrome只有第一个(打印“A fired”)被执行。但是当我在IE6和IE8中运行相同的代码时,两个回调都会执行。这是我的脚本中的一些错误,还是这些浏览器充满了这些错误之一?做clearTimeout()/ clearInterval()保证回调在调用后不会被调用?

+0

作为@qwerty指出你的'VAR了'和'VAR B'分配非常接近,我认为在IE稍慢JavaScript引擎需要更长时间完成你的'log'语句,所以'clearTimeout'调用在函数被调用后发生。在分配'var b'时,为'setTimeout'调用'2 * int',并且您不会看到它被调用,因为有足够的延迟来完成'var a'调用并清除超时。 – 2011-05-02 05:23:42

+0

_Try 2 * int setTimeout call_ - 这没什么好玩的:)在一个复杂的脚本中,你不能保证超时不会同时触发。 – Egorinsk 2011-05-02 06:34:47

+0

@Egorinsk:也许你可以改变这个问题的接受答案? – robocat 2013-04-23 02:48:21

回答

3

我认为正在发生的事情是:

  • JavaScript有一个事件队列。
  • IE处理超时,并排队两个事件。
  • 处理第一个超时事件,并为B调用clearTimeout。但是B的事件已经排队,所以它仍然被触发。
  • 第二超时事件被处理时,和clearTimeout被调用A.

我怀疑在IE中,事件被排队,并调用clearTimeout不会删除从事件队列中的事件。

IE浏览器如何将同时超时队列推入队列也是可能的......诊断基本原因可以通过使用两个不同的超时,x时间使用100%CPU处理循环和排队/插入其他事件(也许可以使用window.postMessage()将事件插入队列并使用window.onMessage()捕获它们)。

我修改了您现有的代码以更好地演示问题。它排队日志项目,而不是立即做它们,因为调用display()会导致布局或渲染发生,这可能很容易引入其他奇怪的干扰。

编辑:您可以使用http://jsbin.com/ucukez/2测试这 - 如果浏览器有故障,那么你得到“在超时炒鱿鱼” “B中的超时炒鱿鱼”。

编辑:这是固定在IE9 - 我无法在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> 
+0

谢谢您的回答。这似乎是众多IE怪异之一,所以我猜这里唯一的工作就是添加一些标志并在运行某些操作之前检查它们。 – Egorinsk 2011-08-25 10:33:46

0

你设置超时正好在同一时间发生,因为它们都是派生的进程你会得到不一致的结果

最好的办法是先测试,看是否超时还是喜欢这个有效:

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); 
+2

但是javascript是单线程的,这两个函数不能同时运行!这很奇怪。但是你的代码似乎修复了这个错误。 – Egorinsk 2011-05-02 05:56:05

+1

@Egorinsk:我同意,但是这是M $的方式,顺便说一句,如果你觉得我回答你的问题,你可以在绿色勾点击旁边的我的回答 – qwertymk 2011-05-02 06:51:12