【问题标题】:Clarifying clearTimeout behavior in IE澄清 IE 中的 clearTimeout 行为
【发布时间】:2011-05-02 04:55:01
【问题描述】:

我有以下代码:

<!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 fire”)被执行。但是当我在 IE6 和 IE8 中运行相同的代码时,两个回调都会被执行。这是我的脚本中的一些错误,还是这些浏览器充满的错误之一? clearTimeout()/clearInterval() 是否保证回调在调用后不会被调用?

【问题讨论】:

  • 正如@qwerty 指出你对var avar b 的分配是如此接近,我认为IE 中稍慢的JavaScript 引擎需要更长的时间来完成你的log 语句等等clearTimeout 调用发生在该函数已被调用之后。在分配var b 时尝试2 * int 调用setTimeout,您不会看到它被调用,因为完成var a 调用并清除超时的延迟足够长。
  • 为 setTimeout 调用尝试 2 * int — 这不好玩 :) 在复杂的脚本中,你不能保证不会同时触发超时。
  • @Egorinsk:也许你可以改变这个问题的接受答案?
  • @robocat 你的答案得分更多我已经改变了接受的答案。

标签: javascript internet-explorer


【解决方案1】:

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

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

【讨论】:

  • 感谢您的回答。这似乎是众多 IE 怪异之一,所以我想这里唯一的工作就是添加一些标志并在运行某些操作之前检查它们。
【解决方案2】:

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

最好的办法是先测试一下超时是否仍然有效,如下所示:

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

【讨论】:

  • 但是javascript是单线程的,这两个函数不能同时运行!这很奇怪。但是你的代码似乎修复了这个错误。
  • @Egorinsk:我同意,但这就是 M$ 的方式,顺便说一句,如果你觉得我回答了你的问题,你可以点击我的答案旁边的绿色对勾
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-08
  • 2019-10-06
  • 1970-01-01
  • 2012-11-21
相关资源
最近更新 更多