0

I have an issue that hold my neck with time interval. I am calculating my time/clock one second at a time with the function below.

Header.prototype= {

 time_changed : function(time){
        var that = this;
        var clock_handle;
        var clock = $('#gmtclock');

        that.time_now = time;
        var increase_time_by = function(interval) {
            that.time_now += interval;
        };
        var update_time = function() {
             clock.html(moment(that.time_now).utc().format("YYYY-MM-DD HH:mm") + " GMT");
        };
        update_time();

        clearInterval(clock_handle);

        clock_handle = setInterval(function() {
            increase_time_by(1000);
            update_time();
        }, 1000);

    },
};

The above works fine and increase my time a second at a time correctly . However. I added another event that fires on web changed or tab navigated.

var start_time;
        var tabChanged = function() {
            if(clock_started === true){
                if (document.hidden || document.webkitHidden) {
                    start_time = moment().valueOf();
                    time_now = page.header.time_now;
                }else {
                    var tnow = (time_now + (moment().valueOf() - start_time));
                    page.header.time_changed(tnow);
                }
            }
        };

        if (typeof document.webkitHidden !== 'undefined') {
            if (document.addEventListener) {
                document.addEventListener("webkitvisibilitychange", tabChanged);
            }
        }

The above fires when ever user leave the page and comes back . It add the delay to the time. However, i notice the second increase rapidly . and very past my timer does not fire very second any more as specified in the clock hand. It add second every milliseconds and fats. Please why this and how do i fix this ? My time run fast and ahead when ever i change tab and returned . Any help would be appreciated

Update

Below is my WS request function.

Header.prototype = {

    start_clock_ws : function(){
            var that = this;

            function init(){
                clock_started = true;
                WS.send({ "time": 1,"passthrough":{"client_time" :  moment().valueOf()}});
            }
            that.run = function(){
                setInterval(init, 900000);
            };

            init();
            that.run();

            return;
        },
        time_counter : function(response){
            var that = this;
            var clock_handle;
            var clock = $('#gmt-clock');
            var start_timestamp = response.time;
            var pass = response.echo_req.passthrough.client_time;

            that.time_now = ((start_timestamp * 1000) + (moment().valueOf() - pass));

            var increase_time = function() {
                that.time_now += (moment().valueOf() - that.time_now);
            };
            var update_time = function() {
                 clock.html(moment(that.time_now).utc().format("YYYY-MM-DD HH:mm") + " GMT");
            };
            update_time();

            clearInterval(clock_handle);

            clock_handle = setInterval(function() {
                increase_time();
                update_time();
            }, 500);
        },

    };

and in my WS open event

if(isReady()=== true){
       if (clock_started === false) {
           page.header.start_clock_ws();
      }
   }

In my WS onmessage event

if(type ==='time'){
   page.header.time_counter(response);
}

Base on your suggestion, i modified my increase_time_by to

var increase_time_by = function() {
      that.time_now += (moment().valueOf() - that.time_now);
   };

It seems fine now. Would test further and see.

Nuru Salihu
  • 4,756
  • 17
  • 65
  • 116
  • Yes this is the issue which i have faced recently, the solution which i did is, i did server call and getting the time interval from there and once the time interval reached to max decided time i stop executing the script. – Amit Shah Dec 17 '15 at 04:30
  • @AmitShah sorry i don't understand the max decided . Its a time and a clock. It should run as far as the user is on the website. The 1000 millse interval is specified in my timer. Why does it changed then ? I am confused. – Nuru Salihu Dec 17 '15 at 04:33
  • 1
    This is a of browser how it handles the script, in chrome it would stop, in mozila it would run fast and in IE it would run slow. – Amit Shah Dec 17 '15 at 04:36
  • 1
    JavaScript is single threaded, unless you take advantage of new features. This means that events triggered like intervals are executed at their earliest convenience. Other code may be processing and delay the execution of that interval. Moral is, don't rely on the accuracy of the time for interval. – teynon Dec 17 '15 at 05:41

1 Answers1

2

Instead of incrementing the clock by the value of the interval, just update the clock to the current time with each pass. Then it won't matter if you fire exactly 1000 ms apart or not.

You actually may want to run more frequently, such as every 500 ms, to give a smoother feel to the clock ticking.

Basically, it comes down to the precision of the timer functions, or lack thereof. Lots of questions on StackOverflow about that - such as this one.


Based on your comments, I believe you are trying to display a ticking clock of UTC time, based on a starting value coming from a web service. That would be something like this:

var time_from_ws = // ... however you want to retrieve it
var delta = moment().diff(time_from_ws);  // the difference between server and client time

// define a function to update the clock
var update_time = function() {
    clock.html(moment.utc().subtract(delta).format("YYYY-MM-DD HH:mm") + " GMT");
};

update_time(); // set it the first time
setInterval(update_time, 500); // get the clock ticking
Community
  • 1
  • 1
Matt Johnson-Pint
  • 230,703
  • 74
  • 448
  • 575
  • Hi Mr Matt, My time comes from WS . I cannot open an instance every second . Also i am wondering the logic behind the 500ms you suggested. If i update the clock every 500ms, would it be precise ? Would my time changed at the right second , every minute ? – Nuru Salihu Dec 17 '15 at 04:40
  • If it comes from your website, you didn't show that here. You showed `moment().valueOf()`, which is identical to `Date.now()` or `new Date().getTime()`. That's the client's clock. If you are actually setting the time by a value from a web service, then you should show that. In that case, take the difference between the client-side clock and keep that as a delta. Then use that delta against the client-side clock as you update the value. – Matt Johnson-Pint Dec 17 '15 at 04:57
  • The 500ms option is just because to make the ticking smoother visually. If you snap to whole seconds but your timer interval isn't aligned precisely with the clock tick, then you might see it stutter a bit. – Matt Johnson-Pint Dec 17 '15 at 04:59
  • Can you please see my update above. Am i doing right ? Testing at the moment. – Nuru Salihu Dec 17 '15 at 05:04
  • I'm confused by your WS call. That looks like you're *sending* the client's time to the server. I thought you were *receiving* the server-time to use on the client - no? – Matt Johnson-Pint Dec 17 '15 at 05:22
  • Hi, i was not sending. The passthrough is an optional paraeter and i use that to calculate the delay and add it to my time . The delay taken between req and response . – Nuru Salihu Dec 17 '15 at 05:24
  • I use it like `var pass = response.echo_req.passthrough.client_time; that.time_now = ((start_timestamp * 1000) + (moment().valueOf() - pass));` – Nuru Salihu Dec 17 '15 at 05:26
  • See my edit - does that help? Sorry, but I'm not following your code. – Matt Johnson-Pint Dec 17 '15 at 05:38
  • sir , it helps . Please see my update above. I put the two functions specifying how i did it now. Following your example. WOuld that be fine or would there be any issue ? Thanks – Nuru Salihu Dec 17 '15 at 05:43
  • I don't understand this part: `that.time_now += (moment().valueOf() - that.time_now);` If you have `a += b - a`, that's the same as `a = a + b - a`, which is just `a = b`. So essentially you're just writing `that.time_now = moment().valueOf()`, which is just using the client time by itself. – Matt Johnson-Pint Dec 17 '15 at 05:56
  • I would remove the `increase_time` function entirely - since that's not what you're really doing. – Matt Johnson-Pint Dec 17 '15 at 05:57
  • Would using moment() only be sufficient or do i need moment().valueOf() ? I understand moment().valueOf() but moment() ? – Nuru Salihu Dec 17 '15 at 06:11
  • `moment()` gives a moment object, rather than a ms number. I showed an example of that in my code. – Matt Johnson-Pint Dec 17 '15 at 06:42