setInterval同时且更频繁地调用回调,直到浏览器停止响应

时间:2012-11-20 06:09:21

标签: javascript setinterval

我有一个jsp页面,它为某些HTML元素设置'timestamp'属性。我使用这些'timestamp'的值来显示格式的时间 - “10秒前更新”(作为工具提示)

我已经创建了一个静态HTML页面来演示我的问题。 这是我的代码:

<html>
    <head>
        <script type = "text/javascript">
            function setTime() {
                var currentDate = new Date();
                var elem = document.getElementsByClassName('supermaxvision_timestamp');
                if(elem) {
                    for (var i = 0; i < elem.length; i++) {
                        var timestamp = elem[i].getAttribute('timestamp');
                        if(timestamp) {
                            var startTimestamp = new Date();
                            startTimestamp.setTime(timestamp)
                            var difference = currentDate.getTime() -startTimestamp.getTime();
                            elem[i].innerHTML = difference + " milliseconds";
                        }
                    }
                }
                setInterval(setTime, 1000);
            }
        </script>
    </head>

    <body>
        <div class='supermaxvision_timestamp' timestamp='1353389123456' ></div>
        <div class='supermaxvision_timestamp' timestamp='1353389234567' ></div>
        <div class='supermaxvision_timestamp' timestamp='1353389345678' ></div>
        <div class='supermaxvision_timestamp' timestamp='1353389456789' ></div>
        <div class='supermaxvision_timestamp' timestamp='1353389567890' ></div>

        <button onclick="setTime()">start</button>
    </body>
</html>

您只需将此代码复制粘贴到文本文件中,然后在浏览器中打开(只需点击“开始”按钮一次)。

问题是我的div的值最初会每秒更新一次(代码 - setInterval(setTime, 1000))。但是慢慢地更新间隔减少并且值立即更新。浏览器在一分钟内停止响应。

我没有在循环中调用setInterval。这可能有什么问题?

此外,此代码在IE中不起作用。

3 个答案:

答案 0 :(得分:3)

setInterval(fn, ms)表示每隔fn毫秒运行ms,从现在开始直到我清除此间隔。但是在每次通话时,你设置一个新的间隔,与最后一个相同。

只需将setInterval更改为setTimeout即可重复,只调用一次提供的功能。 setTimeout可以通过调用递归设置新超时的函数来模拟setInterval。如果您按间隔执行此操作,则会安排越来越多的永不停止的间隔。每次调用自己时,预定间隔的数量加倍。它很快失控了......

或者,您可以将setInterval移出setTime函数并仅调用一次,这将使其每秒调用一次。比如说:

// button calls this.
function startTime() {
  setInterval(setTime);
}

function setTime() {
  // all that code, but minus the setInterval at the end
}

答案 1 :(得分:0)

你正在递归地调用setInterval。每次创建新间隔时,该间隔都会创建一个新间隔。最终浏览器无法处理它。

也许你会喜欢这样的东西?

<button onclick="setInterval(setTime, 1000)">start</button>

答案 2 :(得分:0)

setInterval开始一个重复函数 - 因为它现在是setTime它的循环和逻辑然后每秒调用setTimeout,每个setTimeout调用然后每秒开始另一次重复调用。如果你使用setTimeout,它只会被调用一次,但我的建议是你只需在函数声明之外运行setInterval,如:

<html>
    <head>
        <script type = "text/javascript">
            function GEBCN(cn){
                if(document.getElementsByClassName) // Returns NodeList here
                    return document.getElementsByClassName(cn);

                cn = cn.replace(/ *$/, '');

                if(document.querySelectorAll) // Returns NodeList here
                    return document.querySelectorAll((' ' + cn).replace(/ +/g, '.'));

                cn = cn.replace(/^ */, '');

                var classes = cn.split(/ +/), clength = classes.length;
                var els = document.getElementsByTagName('*'), elength = els.length;
                var results = [];
                var i, j, match;

                for(i = 0; i < elength; i++){
                    match = true;
                    for(j = clength; j--;)
                        if(!RegExp(' ' + classes[j] + ' ').test(' ' + els[i].className + ' '))
                            match = false;
                    if(match)
                        results.push(els[i]);
                }

                // Returns Array here
                return results;
            }
            function setTime() {
                var currentDate = new Date();
                var elem = GEBCN('supermaxvision_timestamp');
                if(elem) {
                    for (var i = 0; i < elem.length; i++) {
                        var timestamp = elem[i].getAttribute('timestamp');
                        if(timestamp) {
                            var startTimestamp = new Date();
                            startTimestamp.setTime(timestamp)
                            var difference = currentDate.getTime() -startTimestamp.getTime();
                            elem[i].innerHTML = difference + " milliseconds";
                        }
                    }
                }
            }
        </script>
    </head>

    <body>
        <div class='supermaxvision_timestamp' timestamp='1353389123456' ></div>
        <div class='supermaxvision_timestamp' timestamp='1353389234567' ></div>
        <div class='supermaxvision_timestamp' timestamp='1353389345678' ></div>
        <div class='supermaxvision_timestamp' timestamp='1353389456789' ></div>
        <div class='supermaxvision_timestamp' timestamp='1353389567890' ></div>
        <button onclick="setInterval(setTime, 1000)">start</button>
    </body>
</html>

此外,这在IE中不起作用的原因是它不能正确支持文档的getElementsByClassName方法。我发现在这里:IE 8: Object doesn't support property or method 'getElementsByClassName'和Rob W也在那里给出了一个很好的解释,但是为了快速回答我已经使用querySelectorAll

修改了上面的代码以便在IE中工作

好的,我刚才说没有意义,但我已经复制了所有的代码,上面是一个工作,测试(在ie和ff)你想要的例子