澄清IE中的clearTimeout行为

问题描述 投票:4回答:2

我有以下代码:

<!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()是否保证在调用后不会调用回调?

javascript internet-explorer
2个回答
3
投票

我认为发生的事情是:

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

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

IE也可能将同步超时推送到队列中的时髦性......可以通过使用两个不同的超时,使用100%CPU处理循环x时间以及通过排队/插入其他来实现诊断根本原因。事件(可能使用window.postMessage()将事件注入队列并使用window.onMessage()捕获它们。

我修改了您现有的代码以更好地演示问题。它将日志项排队而不是立即执行,因为调用display()会导致布局或呈现,这很容易引入其他时髦的干扰。

编辑:您可以使用http://jsbin.com/ucukez/2对此进行测试 - 如果浏览器出现故障,则会出现“在A超时触发”和“在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
投票

您将超时设置为完全同时发生,并且因为它们都是分叉进程,所以会得到不一致的结果

您最好的选择是首先测试超时是否仍然有效,如下所示:

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);
© www.soinside.com 2019 - 2024. All rights reserved.