在IE

2011-05-02 93 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