在显示的模块模式中取消失控的JavaScript超时/间隔

时间:2015-10-26 11:12:56

标签: javascript module instance settimeout setinterval

我有一个相当标准化的揭示模块模式来创建用作实例的对象。有时,在这些模式中,在外部代码中不再使用或引用模块的情况下,需要取消超时或间隔。

此模式的简化示例:

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环境之外的超时。

3 个答案:

答案 0 :(得分:1)

在这种情况下,我会将整个函数包装在包含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非常通用,可以被其他脚本覆盖。

答案 1 :(得分:0)

试一试:更新下面的代码..

var settimer;
function test() {
   clearTimeout(settimer);
   settimer= setTimeout(function () { 
      window.timer = maketimer(); 
   }, 100);   
}

答案 2 :(得分:0)

扩展answer given by @nils,我创建了以下示例,用于构建一个模块,该模块接收单个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节点,但它可以很容易地是一个数字,字符串等。

如果您希望维护文档中一次只有一个实例的规则,则接受的答案非常有用,并且仍然是首选。