我有以下代码:
<!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 :(得分:3)
我认为发生的事情是:
我怀疑在IE中,事件排队并且调用clearTimeout不会从事件队列中删除事件。
IE也可能将同步超时推送到队列中的时间很短......通过使用两个不同的超时,使用100%CPU处理循环x时间,以及通过排队/可以实现诊断根本原因在其他事件中插入(也许可以使用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>
答案 1 :(得分: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);