在显示模块模式中取消失控 JavaScript timeouts/intervals
Cancelling runaway JavaScript timeouts/intervals within a revealing module pattern
我有一个相当标准化的揭示模块模式来创建用作实例的对象。有时,在这些模式中,如果模块不再被使用或在外部代码中引用,则需要取消超时或间隔。
此模式的简化示例:
function test() {
window.timer = maketimer();
}
function maketimer() {
var cls, my;
my = {
increment: 0,
timerid: null,
exec_timer: function() {
my.timerid = window.setInterval(my.time, 2000);
},
time: function() {
console.log("timer: ", my.timerid, my.increment++);
}
},
cls = {
//...
}
my.exec_timer();
return cls;
};
test();
// some time later...
test();
在 test
被调用两次的情况下,无论出于何种原因,变量 window.timer
被替换为 maketimer
的第二个实例,但第一个实例计时器继续 运行.
很多时候,我的模块本质上链接到 DOM 个节点,而且 DOM 个节点经常与旧实例一起删除,所以理论上我可以检查节点不存在或其放置在 DOM 之外,然后在这种情况下取消间隔。
然而,这要通用得多,我希望能够在 DOM 环境之外处理超时。
试一试:在下面更新您的代码..
var settimer;
function test() {
clearTimeout(settimer);
settimer= setTimeout(function () {
window.timer = maketimer();
}, 100);
}
在这种情况下,我会将整个函数包装在一个包含 instance
变量的 IIFE 中。在其中,您保存计时器。而且每启动一个新的,旧的就被销毁:
(function(window) {
var timerInstance = null;
window.maketimer = function() {
var cls, my;
if(timerInstance) {
timerInstance.destroyInstance();
}
my = {
increment: 0,
timerid: null,
exec_timer: function() {
my.timerid = window.setInterval(my.time, 2000);
},
time: function() {
console.log("timer: ", my.timerid, my.increment++);
},
destroyInstance: function() {
window.clearInterval(my.timerid);
}
},
cls = {
//...
}
my.exec_timer();
timerInstance = my;
return cls;
}
})(window);
function test() {
window.timer = maketimer();
}
test();
test();
出于好奇,为什么需要将实例放在全局变量上? window.timer
非常通用,可以被其他脚本覆盖。
在 上展开,我创建了以下示例,用于构建一个接受单个 DOM 节点的模块,如果 DOM节点已被使用:
<div id="element1">[code here that may be updated with XHR]</div>
<div id="element2">[code here that may be updated with XHR]</div>
(function(window) {
var timerInstances = [];
window.maketimer = function(element) {
var cls, my, a;
// find instances where the passed element matches
for (a = 0; a < timerInstances.length; a += 1) {
if (timerInstances[a].element === element) {
console.log("instance already exists for element", element, "destroying...");
timerInstances[a].in.destroyInstance();
}
}
my = {
increment: 0,
timerid: null,
exec_timer: function() {
my.timerid = window.setInterval(my.time, 2000);
},
time: function() {
console.log("timer: ", my.timerid, my.increment++);
},
destroyInstance: function() {
window.clearInterval(my.timerid);
}
},
cls = {
//...
}
my.exec_timer();
timerInstances.push({
'element': element,
'in': my
});
return cls;
}
})(window);
function test(element) {
window.timer = maketimer(element);
}
test(document.getElementById("element1")); // produces 1 timer
test(document.getElementById("element1")); // cancels last, produces 1 timer
test(document.getElementById("element2")); // produces 1 timer
这里的标识参数可以是任何东西——在本例中它是一个 DOM 节点,但它很容易是一个数字、字符串等。
接受的答案非常有帮助,如果您希望在文档中保持一次只有一个实例的规则,仍然是首选。
我有一个相当标准化的揭示模块模式来创建用作实例的对象。有时,在这些模式中,如果模块不再被使用或在外部代码中引用,则需要取消超时或间隔。
此模式的简化示例:
function test() {
window.timer = maketimer();
}
function maketimer() {
var cls, my;
my = {
increment: 0,
timerid: null,
exec_timer: function() {
my.timerid = window.setInterval(my.time, 2000);
},
time: function() {
console.log("timer: ", my.timerid, my.increment++);
}
},
cls = {
//...
}
my.exec_timer();
return cls;
};
test();
// some time later...
test();
在 test
被调用两次的情况下,无论出于何种原因,变量 window.timer
被替换为 maketimer
的第二个实例,但第一个实例计时器继续 运行.
很多时候,我的模块本质上链接到 DOM 个节点,而且 DOM 个节点经常与旧实例一起删除,所以理论上我可以检查节点不存在或其放置在 DOM 之外,然后在这种情况下取消间隔。
然而,这要通用得多,我希望能够在 DOM 环境之外处理超时。
试一试:在下面更新您的代码..
var settimer;
function test() {
clearTimeout(settimer);
settimer= setTimeout(function () {
window.timer = maketimer();
}, 100);
}
在这种情况下,我会将整个函数包装在一个包含 instance
变量的 IIFE 中。在其中,您保存计时器。而且每启动一个新的,旧的就被销毁:
(function(window) {
var timerInstance = null;
window.maketimer = function() {
var cls, my;
if(timerInstance) {
timerInstance.destroyInstance();
}
my = {
increment: 0,
timerid: null,
exec_timer: function() {
my.timerid = window.setInterval(my.time, 2000);
},
time: function() {
console.log("timer: ", my.timerid, my.increment++);
},
destroyInstance: function() {
window.clearInterval(my.timerid);
}
},
cls = {
//...
}
my.exec_timer();
timerInstance = my;
return cls;
}
})(window);
function test() {
window.timer = maketimer();
}
test();
test();
出于好奇,为什么需要将实例放在全局变量上? window.timer
非常通用,可以被其他脚本覆盖。
在
<div id="element1">[code here that may be updated with XHR]</div>
<div id="element2">[code here that may be updated with XHR]</div>
(function(window) {
var timerInstances = [];
window.maketimer = function(element) {
var cls, my, a;
// find instances where the passed element matches
for (a = 0; a < timerInstances.length; a += 1) {
if (timerInstances[a].element === element) {
console.log("instance already exists for element", element, "destroying...");
timerInstances[a].in.destroyInstance();
}
}
my = {
increment: 0,
timerid: null,
exec_timer: function() {
my.timerid = window.setInterval(my.time, 2000);
},
time: function() {
console.log("timer: ", my.timerid, my.increment++);
},
destroyInstance: function() {
window.clearInterval(my.timerid);
}
},
cls = {
//...
}
my.exec_timer();
timerInstances.push({
'element': element,
'in': my
});
return cls;
}
})(window);
function test(element) {
window.timer = maketimer(element);
}
test(document.getElementById("element1")); // produces 1 timer
test(document.getElementById("element1")); // cancels last, produces 1 timer
test(document.getElementById("element2")); // produces 1 timer
这里的标识参数可以是任何东西——在本例中它是一个 DOM 节点,但它很容易是一个数字、字符串等。
接受的答案非常有帮助,如果您希望在文档中保持一次只有一个实例的规则,仍然是首选。