I'm using the wonderful reveal.js library to create a HTML slideshow. My only problem is that I need it to synchronise across multiple devices.
At the moment I am making a AJAX request to the the time from the server and keep an internal clock for the page.
function syncTime() {
// Set up our time object, synced by the HTTP DATE header
// Fetch the page over JS to get just the headers
console.log("syncing time")
var r = new XMLHttpRequest();
r.open('HEAD', document.location, false);
r.send(null);
var timestring = r.getResponseHeader("DATE");
systemtime = new Date(timestring); // Set the time to the date sent from the server
}
Whilst this gets me within 1 or so seconds of accuracy, I need to do better. The difference is really noticeable when the slideshow is auto advancing.
The code is going to be running all on the same platform, so cross-browser compatibility is nothing to worry about.
Here's what I've managed to put together
Any ideas?
How about a different approach: who cares about time? (You're not going to reliably sync the system clock with JavaScript.)
Instead, use a Node server with socket.io to synchronize when your clients advance the slideshow. Instead of the clients deciding when to advance, the server tells them to.
This approach comes with the added bonus of being able to manually fiddle with the slideshow while it's running. In the example that follows, I've added a Next button that causes all connected clients to immediately advance to the next slide.
app.js
views/index.html
This file is processed as a doT template.
Copy these two files into a folder, then run
and navigate to
http://localhost:70
in several different windows, then see the magic.I'm extensively using the COMET pattern here for my real time web application.
To use that in your case you'd need the clients to open an AJAX request to the server and wait for an answer. As soon as it comes the client has to change slides.
On the server you have to hold back all answers till it's time to change slides. (You could be more advanced and delay afterwards on the client for the same time each, but that's most likely not necessary). I can't show you sample code for that here as I don't know what's available to you.
So you are effectively creating an orchestra where the server plays the conductor and all clients are listening to him.
Timing is then determined by the ability of the server to answer the requests at (nearly) the same time plus the network latency.
Usually the clients should be in the same part of the network so latency might be very similar - and the absolute value doesn't hurt here, only the variation.
And there might also be an additional trick helping: don't change the slides with a hard replacement, blend them. This will blur the change so that the eye can't catch the little timing differences that you'll always have.
(If you can't have the server playing conductor you're likely to have to use the solution by MikeWyatt - probably with a few requests and averaging the result, depending on the network setup. In a LAN one request might be enough, going over the full internet a bit over averaging won't hurt...)
I'm glad you found a satisfactory answer to your question. I had a similar need to synchronize the browser with the server's clock and was determined to achieve it with better than 1 second accuracy like you were. I've written code to do this and am posting this answer here in case anyone else needs the solution too.
The code is called ServerDate and is freely available for download. Here's part of the README. Notice that I achieved 108 ms precision in my example:
You can use
ServerDate
as you would use theDate
function or one of its instances, e.g.:There is also a new method to get the precision of ServerDate's estimate of the server's clock (in milliseconds):
You can see the difference between the server's clock and the browsers clock, in milliseconds:
You can't really sync up with the server. Measuring the time your server request needs (as MikeWyatt suggested) is not a good indicator on the latency.
Only your server knows when he responds a request. Therefore, it should send that information back with the answer. With
Date.now() - new Date(timestringOfServerResponse)
you can measure the latency exactly. Yet I'm not sure why you would need that value.To sync an app between mulitiple devices, the server should send them which action to perform when. The "when" should not be "as soon as you get my response", but a exact timestamp. As far as the system clocks of your devices are accurate and synced (they usually are), the app will run its methods synchrounously, because it knows what to happen when (or at least: what should have happened then, and it can interpolate what to happen "now").
Measure the elapsed time between sending the request and getting back the response. Then, divide that value by 2. That gives you a rough value of one-way latency. If you add that to the time value from the server, you'll be closer to the true server time.
Something like this should work:
Interesting aside: John Resig has a good article on the accuracy of Javascript timing.
It shouldn't cause a problem in this case, since you're only concerned about your time being off by ~1 second. A 15 ms difference shouldn't have much effect.