-2

I've a jsp page which sets 'timestamp' attribute to certain HTML elements. I use the value of these 'timestamp' to display time elapsed in the format - "updated 10 seconds ago" (as tooltips)

I've created a static HTML page for the demonstration of my issue. This is my code:

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

you can just copy paste this code into a text file and open it in a browser (click 'start' button only once).

The problem is that initially the values of my div will update once every second ( as the code - setInterval(setTime, 1000)). But slowly the update interval decreases and values gets updated instantaneously. And within a minute the browser stops responding.

I'm not calling setInterval from within the loop. What is possibly wrong here?

Also, this code doesn't work in IE.

smv
  • 21
  • 2

3 Answers3

3

setInterval(fn, ms) says run fn every ms milliseconds, from now until I clear this interval. But on each call, you set a new interval, identical to the last.

So simply change setInterval to setTimeout which does not repeat, and only calls the function provided once. setTimeout can emulate setInterval by calling a function that sets a new timeout recursively. If you do that with intervals, you schedule more and more intervals that never stop. And each time it calls itself, the number of scheduled intervals double. It gets out of hand quickly...

Alternatively, you can move the setInterval out of the setTime function and only call it once, which will keep it being called every second. Like say:

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

function setTime() {
  // all that code, but minus the setInterval at the end
}
Alex Wayne
  • 178,991
  • 47
  • 309
  • 337
0

You're calling setInterval recursively. Every time a new interval is created, that interval creates a new interval. Eventually the browser cannot handle it.

Maybe you would rather something like this?

<button onclick="setInterval(setTime, 1000)">start</button>
John
  • 2,675
  • 2
  • 18
  • 19
  • do you mean the change is not enough because the setInterval would still be in the setTime function? Apart from that it looks fine, this is the same thing I thought when I looked at it – Chris O'Kelly Nov 20 '12 at 06:21
  • thanks for the answer. This works. I mistook `setInterval` as `setTimeout`. No wonder I got 3 down votes. :P Any Thing on I.E. part? – smv Nov 20 '12 at 06:26
  • see my answer for IE, or http://stackoverflow.com/questions/10484467/ie-8-object-doesnt-support-property-or-method-getelementsbyclassname – Chris O'Kelly Nov 20 '12 at 06:27
  • `var elem = document.querySelectorAll('.supermaxvision_timestamp');` works in all browsers except in IE i get the error: `Object doesn't support property or method 'querySelectorAll'` – smv Nov 20 '12 at 06:37
  • read the whole of my answer - querySelectorAll is not in IE either, only in JQuery. My answer now includes a replacement function which I copied from ascii-lime in one of his answers – Chris O'Kelly Nov 20 '12 at 06:45
0

setInterval begins a repeating function - as it is right now setTime does it's loop and logic then calls setTimeout every second, each setTimeout call then starts another repeated call to itself every second. if you use setTimeout instead, it will be called once only, but my suggestion would be that instead you simply run setInterval outside your function declaration, like:

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

Also, the reason this is not working in IE is that it does not properly support the getElementsByClassName method of document. I found that out here: IE 8: Object doesn't support property or method 'getElementsByClassName' and Rob W also gives a good explanation there, but for a quick answer I have modified my code above to work in IE, using querySelectorAll

OK, I just said there was no point, but I've copied all the code here anyway, above is a working, tested (on ie and ff) example of what you want

Community
  • 1
  • 1
Chris O'Kelly
  • 1,863
  • 2
  • 18
  • 35