Synchronized time counter (timer)

468 views
Skip to first unread message

Miroslav Hibler

unread,
Jul 16, 2013, 1:22:02 PM7/16/13
to fireba...@googlegroups.com
Hi guys!

I need a time counter (timer) that will continuously show time spent in session between two parties, let's call them: Master and Slave.

Only Master can manage the timer while Slave can only see it's state.

Master can start, stop and reset the timer at any desired point in time as well as update it on a one second interval.

The technique I've came up with seems to be working okay (as expected) for Master but on the Slave side it very often "misses the bits" as (I presume) updates are getting delayed and then grouped in "chunks":

function timer( callBack ) {
var currentTimer; 
var sessionTimer = new Firebase( "https://SampleTimer.firebaseIO-demo.com" );
sessionTimer.on( "value", function ( timer ) {
if ( timer.val() === null ) {
if ( _isMaster() ) sessionTimer.set( 0 );
} else { 
currentTimer = timer.val();
callBack( currentTimer );
}
});
if ( _isMaster() ) {
var masterTimer = window.setInterval( function() {
sessionTimer.set( currentTimer + 1 ) );
}, 1000 );
}
}

Now, how should I implement this so that both sides are synchronized - showing the very same state at any given point in time?

Thanks,
Miro

Miroslav Hibler

unread,
Jul 16, 2013, 1:28:18 PM7/16/13
to fireba...@googlegroups.com
Sorry, there's a typo in:

sessionTimer.set( currentTimer + 1 ) );

which should be:

sessionTimer.set( currentTimer + 1 );


Miro

Michael Lehenbauer

unread,
Jul 16, 2013, 1:41:37 PM7/16/13
to fireba...@googlegroups.com
Can you clarify what you mean by "misses the bits"?  When I run this code in two browsers locally, it works fine and there's only ~65ms of latency between when the master sets the time and when the "slave" receives it (I just console.logged "new Date().getTime()" for when the master and slave each saw the timestamp and they were only off by 65ms).

So it seems to be working great for me.  To get more precise than that, you'll have to do some sort of latency estimation / compensation technique to try to adjust for the network latency (e.g. see how ntp does it)...

-Michael


--
You received this message because you are subscribed to the Google Groups "Firebase Google Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to firebase-tal...@googlegroups.com.
To post to this group, send email to fireba...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Michael "Kato" Wulf

unread,
Jul 16, 2013, 1:47:03 PM7/16/13
to fireba...@googlegroups.com
Miro,

setTimeout() and setInterval()'s timing is not guaranteed in JavaScript or V8. John Resig wrote a wonderful article that taught me tons about JS timers. That should cover all the whys.

There is no perfect way to get them exactly synced because network latency is always going to create some discrepancy (not that it's going to be easily detected by humans).

I'm using timers on some of my projects and what I've found works best is to use an algorithm like the following:
  1. Use an ends_at time as the base
  2. Adjust all clients target end time using .info/serverTimeOffset
  3. Make each client run its own timer every second to update
  4. Sync the timers by using a time_remaining that updates every few seconds from the master
You can also make the timer look smooth by simply storing the master value in a variable and then, on the client, updating it once a second; this will help prevent the occasional slips when the server's send event is slightly delayed.

However, every time the client is busy, the interval may arrive late (or even early in some browser versions), so there's no way to completely eradicate temporary slipping.

Cheers,

On Tue, Jul 16, 2013 at 10:28 AM, Miroslav Hibler <mhi...@gmail.com> wrote:

--
Message has been deleted

Miroslav Hibler

unread,
Jul 16, 2013, 2:09:20 PM7/16/13
to fireba...@googlegroups.com
Hi Kato,

Thank you for your reply too :)

I'm not as much concerned about the accuracy of timers as long as both sides show the same state.

I'm worrying about the human perception of slipping timer especially when it's connected to payments - it may raise some questions ;)

I've also tried a version of #3 but missed on other points, so I'll give it a try.

Thank you very much!

Cheers,
Miro

Michael "Kato" Wulf

unread,
Jul 16, 2013, 3:40:09 PM7/16/13
to fireba...@googlegroups.com
Miroslav,

Here is a working example you can try out. It seems to keep good time between the clients using only an end time as reference point. This is very similar to what I successfully use in my projects (I'd just send you that but it's embedded in my Backbone build and I can't see a way to easily abstract it).


Cheers,



Michael "Kato" Wulf


Miroslav Hibler

unread,
Jul 16, 2013, 6:08:11 PM7/16/13
to fireba...@googlegroups.com
Kato,

I appreciate your example and I understand that it's only an abstract of the functionality, so it needs modifications and customizations (one would be adaptation to time-zone difference).
Nevertheless, I've already learned a lot from it, thank you :)

But, before diving into further development, I'd like to make a few points here:
  1. We need to count the time spent in the session (which may be paused/resumed countless times), NOT the real (natural) time passed; not that it negates your example, I'm merely making a point here ;)
  2. One can't have uninterrupted ("slipping", "freezing",...) timers (counters) due to the very nature of Javascript - single threaded asynchronous event handling;
  3. Client-side timers (as in your example) may wonder off clueless (and eventually time-out!) upon network failure (lack of synchronization), which in my case is not acceptable - in this particular case it's more acceptable for disconnected session timer display to remain "frozen" than to selfishly time-out (besides, we're doing some client-side tasks after session time-out);
  4. I think it's better to have a timer value saved and updated via .set() and distributed to clients upon their reconnection, thus "synchronizing" them to the master; UX-wise, it's much better to see it "frozen then resumed" instead of deja-vu-esque "gone to zero and suddenly counting again"; furthermore, saved counter keeps the value even in case when both parties hit the dust, so they can pick up where they left off;
  5. We'll need some more FAQ/FAA (aka WTF) on our site... ;)
Cheers,
Miro
Reply all
Reply to author
Forward
0 new messages