Sync JS time between multiple devices












23















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?










share|improve this question





























    23















    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?










    share|improve this question



























      23












      23








      23


      12






      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?










      share|improve this question
















      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?







      javascript time synchronization






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited May 20 '12 at 12:40







      Josh Hunt

















      asked May 14 '12 at 15:02









      Josh HuntJosh Hunt

      4,182236792




      4,182236792
























          5 Answers
          5






          active

          oldest

          votes


















          19





          +500









          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



          var express = require('express')
          , app = express.createServer()
          , io = require('socket.io').listen(app)
          , doT = require('dot')
          , slide = 0
          , slides = [
          'http://placekitten.com/700/400?image=13',
          'http://placekitten.com/700/400?image=14',
          'http://placekitten.com/700/400?image=15',
          'http://placekitten.com/700/400?image=16',
          'http://placekitten.com/700/400?image=1',
          'http://placekitten.com/700/400?image=2',
          'http://placekitten.com/700/400?image=3',
          'http://placekitten.com/700/400?image=4',
          'http://placekitten.com/700/400?image=5',
          'http://placekitten.com/700/400?image=6',
          'http://placekitten.com/700/400?image=7',
          'http://placekitten.com/700/400?image=8',
          'http://placekitten.com/700/400?image=9',
          'http://placekitten.com/700/400?image=10',
          'http://placekitten.com/700/400?image=11',
          'http://placekitten.com/700/400?image=12',
          ];

          app.listen(70); // listen on port 70

          app.register('.html', doT); // use doT to render templates
          app.set('view options', {layout:false}); // keep it simple
          doT.templateSettings.strip=false; // don't strip line endings from template file

          app.get('/', function(req, res) {
          res.render('index.html', { slide: slide, slides: slides });
          });

          app.post('/next', function(req, res) {
          next();
          res.send(204); // No Content
          });

          setInterval(next, 4000); // advance slides every 4 seconds

          function next() {
          if (++slide >= slides.length) slide = 0;
          io.sockets.emit('slide', slide);
          }


          views/index.html



          This file is processed as a doT template.



          <!DOCTYPE html>
          <html>
          <head>
          <title>Synchronized Slideshow</title>
          <script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
          <script src="/socket.io/socket.io.js"></script>
          <script>
          var curslide = {{=it.slide}}; // the slide the server is currently on.

          $(function() {
          $('#slide' + curslide).css('left',0);

          $('#next').click(function() {
          $.post('/next');
          });
          });

          var socket = io.connect('http://localhost:70');
          socket.on('slide', function(slide) {
          $('#slide' + curslide).animate({left:-700}, 400);
          $('#slide' + slide).css('left',700).show().animate({left:0}, 400);
          curslide = slide;
          });
          </script>
          <style>
          #slideshow, .slide { width:700px; height:400px; overflow:hidden; position:relative; }
          .slide { position:absolute; top:0px; left:700px; }
          </style>
          </head>
          <body>
          <div id="slideshow">
          {{~it.slides :url:i}}
          <div id="slide{{=i}}" class="slide"><img src="{{=url}}"></div>
          {{~}}
          </div>
          <button id="next">Next &gt;</button>
          </body>
          </html>


          Copy these two files into a folder, then run



          $ npm install express socket.io dot
          $ node app.js


          and navigate to http://localhost:70 in several different windows, then see the magic.






          share|improve this answer


























          • Love this answer! Ignoring my question to get to the same objective. I'm going to take this approach and see what I can get out of it!

            – Josh Hunt
            May 20 '12 at 2:27











          • And kudos for the demo link!

            – Josh Hunt
            May 20 '12 at 2:33











          • I got a couple of errors running this with the latest version of Express. Only when I pinned it to version 2.5.10 and reinstalled did it work. Also, I had to run sudo node app.js

            – skube
            Dec 30 '16 at 15:27






          • 1





            Yeah, this is very old and express obviously has many breaking changes between v2 and v4. The need for sudo comes from listening on port 70, change that to something >1024 to fix.

            – josh3736
            Jan 2 '17 at 2:28



















          22














          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:



          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();
          var start = (new Date).getTime();

          r.open('HEAD', document.location, false);
          r.onreadystatechange = function()
          {
          if (r.readyState != 4)
          {
          return;
          }
          var latency = (new Date).getTime() - start;
          var timestring = r.getResponseHeader("DATE");

          // Set the time to the **slightly old** date sent from the
          // server, then adjust it to a good estimate of what the
          // server time is **right now**.
          systemtime = new Date(timestring);
          systemtime.setMilliseconds(systemtime.getMilliseconds() + (latency / 2))
          };
          r.send(null);
          }


          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.






          share|improve this answer


























          • An amazing answer! Pretty sure this is the best solution available, but im going to add a bounty on to see if I can attract some other solutions.

            – Josh Hunt
            May 16 '12 at 8:14






          • 4





            This is how I would do it. The only difference being that I would do a sync call several times (i.e. 10 times) and then use the systemtime from the call with the lowest latency. Indeed, the higher the latency, the more impact you have from the fact that the distribution between from-client-to-server-time and from-server-to-client-time is not exactly 1:1.

            – Willem Mulder
            May 19 '12 at 12:50











          • Is there a better option than dividing response time by 2? In some of my tests the server blocks for awhile but then returns quickly. So maybe the trip time was 200ms, but the time returned is only 20ms off. Does that make sense?

            – jocull
            Jul 23 '13 at 15:27











          • Useful code. It's giving better results than "ServerDate" library. :)

            – xdevnull
            Dec 25 '18 at 20:08



















          11














          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 the Date function or one of its
          instances, e.g.:



          > ServerDate()
          "Mon Aug 13 2012 20:26:34 GMT-0300 (ART)"

          > ServerDate.now()
          1344900478753

          > ServerDate.getMilliseconds()
          22


          There is also a new method to get the precision of ServerDate's estimate of the
          server's clock (in milliseconds):



          > ServerDate.toLocaleString() + " ± " + ServerDate.getPrecision() + " ms"
          "Tue Aug 14 01:01:49 2012 ± 108 ms"


          You can see the difference between the server's clock and the browsers clock, in milliseconds:



          > ServerDate - new Date()
          39





          share|improve this answer

































            0














            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").






            share|improve this answer



















            • 1





              That's exactly how this is functioning. The page waits until the correct time before performing an action to ensure it is syncd across devices. The problem comes down to the fact that I have two iPads next to each other which are set to sync time with time servers, yet are 1 second apart.

              – Josh Hunt
              May 15 '12 at 11:20











            • So you want to implement a time server in javascript, to sync "custom system times"?

              – Bergi
              May 15 '12 at 11:25








            • 2





              @Bergi, you're erroneously assuming that the client's clock matches the clock on the server. They are practically guaranteed to be different, probably by multiple seconds or minutes. Adjusting for latency isn't perfect, but it will get you pretty close. In the worst case, you'll be off by the full round-trip time, if one of the trips was instantaneous.

              – MikeWyatt
              May 16 '12 at 3:47



















            0














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






            share|improve this answer























              Your Answer






              StackExchange.ifUsing("editor", function () {
              StackExchange.using("externalEditor", function () {
              StackExchange.using("snippets", function () {
              StackExchange.snippets.init();
              });
              });
              }, "code-snippets");

              StackExchange.ready(function() {
              var channelOptions = {
              tags: "".split(" "),
              id: "1"
              };
              initTagRenderer("".split(" "), "".split(" "), channelOptions);

              StackExchange.using("externalEditor", function() {
              // Have to fire editor after snippets, if snippets enabled
              if (StackExchange.settings.snippets.snippetsEnabled) {
              StackExchange.using("snippets", function() {
              createEditor();
              });
              }
              else {
              createEditor();
              }
              });

              function createEditor() {
              StackExchange.prepareEditor({
              heartbeatType: 'answer',
              autoActivateHeartbeat: false,
              convertImagesToLinks: true,
              noModals: true,
              showLowRepImageUploadWarning: true,
              reputationToPostImages: 10,
              bindNavPrevention: true,
              postfix: "",
              imageUploader: {
              brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
              contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
              allowUrls: true
              },
              onDemand: true,
              discardSelector: ".discard-answer"
              ,immediatelyShowMarkdownHelp:true
              });


              }
              });














              draft saved

              draft discarded


















              StackExchange.ready(
              function () {
              StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f10585910%2fsync-js-time-between-multiple-devices%23new-answer', 'question_page');
              }
              );

              Post as a guest















              Required, but never shown

























              5 Answers
              5






              active

              oldest

              votes








              5 Answers
              5






              active

              oldest

              votes









              active

              oldest

              votes






              active

              oldest

              votes









              19





              +500









              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



              var express = require('express')
              , app = express.createServer()
              , io = require('socket.io').listen(app)
              , doT = require('dot')
              , slide = 0
              , slides = [
              'http://placekitten.com/700/400?image=13',
              'http://placekitten.com/700/400?image=14',
              'http://placekitten.com/700/400?image=15',
              'http://placekitten.com/700/400?image=16',
              'http://placekitten.com/700/400?image=1',
              'http://placekitten.com/700/400?image=2',
              'http://placekitten.com/700/400?image=3',
              'http://placekitten.com/700/400?image=4',
              'http://placekitten.com/700/400?image=5',
              'http://placekitten.com/700/400?image=6',
              'http://placekitten.com/700/400?image=7',
              'http://placekitten.com/700/400?image=8',
              'http://placekitten.com/700/400?image=9',
              'http://placekitten.com/700/400?image=10',
              'http://placekitten.com/700/400?image=11',
              'http://placekitten.com/700/400?image=12',
              ];

              app.listen(70); // listen on port 70

              app.register('.html', doT); // use doT to render templates
              app.set('view options', {layout:false}); // keep it simple
              doT.templateSettings.strip=false; // don't strip line endings from template file

              app.get('/', function(req, res) {
              res.render('index.html', { slide: slide, slides: slides });
              });

              app.post('/next', function(req, res) {
              next();
              res.send(204); // No Content
              });

              setInterval(next, 4000); // advance slides every 4 seconds

              function next() {
              if (++slide >= slides.length) slide = 0;
              io.sockets.emit('slide', slide);
              }


              views/index.html



              This file is processed as a doT template.



              <!DOCTYPE html>
              <html>
              <head>
              <title>Synchronized Slideshow</title>
              <script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
              <script src="/socket.io/socket.io.js"></script>
              <script>
              var curslide = {{=it.slide}}; // the slide the server is currently on.

              $(function() {
              $('#slide' + curslide).css('left',0);

              $('#next').click(function() {
              $.post('/next');
              });
              });

              var socket = io.connect('http://localhost:70');
              socket.on('slide', function(slide) {
              $('#slide' + curslide).animate({left:-700}, 400);
              $('#slide' + slide).css('left',700).show().animate({left:0}, 400);
              curslide = slide;
              });
              </script>
              <style>
              #slideshow, .slide { width:700px; height:400px; overflow:hidden; position:relative; }
              .slide { position:absolute; top:0px; left:700px; }
              </style>
              </head>
              <body>
              <div id="slideshow">
              {{~it.slides :url:i}}
              <div id="slide{{=i}}" class="slide"><img src="{{=url}}"></div>
              {{~}}
              </div>
              <button id="next">Next &gt;</button>
              </body>
              </html>


              Copy these two files into a folder, then run



              $ npm install express socket.io dot
              $ node app.js


              and navigate to http://localhost:70 in several different windows, then see the magic.






              share|improve this answer


























              • Love this answer! Ignoring my question to get to the same objective. I'm going to take this approach and see what I can get out of it!

                – Josh Hunt
                May 20 '12 at 2:27











              • And kudos for the demo link!

                – Josh Hunt
                May 20 '12 at 2:33











              • I got a couple of errors running this with the latest version of Express. Only when I pinned it to version 2.5.10 and reinstalled did it work. Also, I had to run sudo node app.js

                – skube
                Dec 30 '16 at 15:27






              • 1





                Yeah, this is very old and express obviously has many breaking changes between v2 and v4. The need for sudo comes from listening on port 70, change that to something >1024 to fix.

                – josh3736
                Jan 2 '17 at 2:28
















              19





              +500









              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



              var express = require('express')
              , app = express.createServer()
              , io = require('socket.io').listen(app)
              , doT = require('dot')
              , slide = 0
              , slides = [
              'http://placekitten.com/700/400?image=13',
              'http://placekitten.com/700/400?image=14',
              'http://placekitten.com/700/400?image=15',
              'http://placekitten.com/700/400?image=16',
              'http://placekitten.com/700/400?image=1',
              'http://placekitten.com/700/400?image=2',
              'http://placekitten.com/700/400?image=3',
              'http://placekitten.com/700/400?image=4',
              'http://placekitten.com/700/400?image=5',
              'http://placekitten.com/700/400?image=6',
              'http://placekitten.com/700/400?image=7',
              'http://placekitten.com/700/400?image=8',
              'http://placekitten.com/700/400?image=9',
              'http://placekitten.com/700/400?image=10',
              'http://placekitten.com/700/400?image=11',
              'http://placekitten.com/700/400?image=12',
              ];

              app.listen(70); // listen on port 70

              app.register('.html', doT); // use doT to render templates
              app.set('view options', {layout:false}); // keep it simple
              doT.templateSettings.strip=false; // don't strip line endings from template file

              app.get('/', function(req, res) {
              res.render('index.html', { slide: slide, slides: slides });
              });

              app.post('/next', function(req, res) {
              next();
              res.send(204); // No Content
              });

              setInterval(next, 4000); // advance slides every 4 seconds

              function next() {
              if (++slide >= slides.length) slide = 0;
              io.sockets.emit('slide', slide);
              }


              views/index.html



              This file is processed as a doT template.



              <!DOCTYPE html>
              <html>
              <head>
              <title>Synchronized Slideshow</title>
              <script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
              <script src="/socket.io/socket.io.js"></script>
              <script>
              var curslide = {{=it.slide}}; // the slide the server is currently on.

              $(function() {
              $('#slide' + curslide).css('left',0);

              $('#next').click(function() {
              $.post('/next');
              });
              });

              var socket = io.connect('http://localhost:70');
              socket.on('slide', function(slide) {
              $('#slide' + curslide).animate({left:-700}, 400);
              $('#slide' + slide).css('left',700).show().animate({left:0}, 400);
              curslide = slide;
              });
              </script>
              <style>
              #slideshow, .slide { width:700px; height:400px; overflow:hidden; position:relative; }
              .slide { position:absolute; top:0px; left:700px; }
              </style>
              </head>
              <body>
              <div id="slideshow">
              {{~it.slides :url:i}}
              <div id="slide{{=i}}" class="slide"><img src="{{=url}}"></div>
              {{~}}
              </div>
              <button id="next">Next &gt;</button>
              </body>
              </html>


              Copy these two files into a folder, then run



              $ npm install express socket.io dot
              $ node app.js


              and navigate to http://localhost:70 in several different windows, then see the magic.






              share|improve this answer


























              • Love this answer! Ignoring my question to get to the same objective. I'm going to take this approach and see what I can get out of it!

                – Josh Hunt
                May 20 '12 at 2:27











              • And kudos for the demo link!

                – Josh Hunt
                May 20 '12 at 2:33











              • I got a couple of errors running this with the latest version of Express. Only when I pinned it to version 2.5.10 and reinstalled did it work. Also, I had to run sudo node app.js

                – skube
                Dec 30 '16 at 15:27






              • 1





                Yeah, this is very old and express obviously has many breaking changes between v2 and v4. The need for sudo comes from listening on port 70, change that to something >1024 to fix.

                – josh3736
                Jan 2 '17 at 2:28














              19





              +500







              19





              +500



              19




              +500





              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



              var express = require('express')
              , app = express.createServer()
              , io = require('socket.io').listen(app)
              , doT = require('dot')
              , slide = 0
              , slides = [
              'http://placekitten.com/700/400?image=13',
              'http://placekitten.com/700/400?image=14',
              'http://placekitten.com/700/400?image=15',
              'http://placekitten.com/700/400?image=16',
              'http://placekitten.com/700/400?image=1',
              'http://placekitten.com/700/400?image=2',
              'http://placekitten.com/700/400?image=3',
              'http://placekitten.com/700/400?image=4',
              'http://placekitten.com/700/400?image=5',
              'http://placekitten.com/700/400?image=6',
              'http://placekitten.com/700/400?image=7',
              'http://placekitten.com/700/400?image=8',
              'http://placekitten.com/700/400?image=9',
              'http://placekitten.com/700/400?image=10',
              'http://placekitten.com/700/400?image=11',
              'http://placekitten.com/700/400?image=12',
              ];

              app.listen(70); // listen on port 70

              app.register('.html', doT); // use doT to render templates
              app.set('view options', {layout:false}); // keep it simple
              doT.templateSettings.strip=false; // don't strip line endings from template file

              app.get('/', function(req, res) {
              res.render('index.html', { slide: slide, slides: slides });
              });

              app.post('/next', function(req, res) {
              next();
              res.send(204); // No Content
              });

              setInterval(next, 4000); // advance slides every 4 seconds

              function next() {
              if (++slide >= slides.length) slide = 0;
              io.sockets.emit('slide', slide);
              }


              views/index.html



              This file is processed as a doT template.



              <!DOCTYPE html>
              <html>
              <head>
              <title>Synchronized Slideshow</title>
              <script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
              <script src="/socket.io/socket.io.js"></script>
              <script>
              var curslide = {{=it.slide}}; // the slide the server is currently on.

              $(function() {
              $('#slide' + curslide).css('left',0);

              $('#next').click(function() {
              $.post('/next');
              });
              });

              var socket = io.connect('http://localhost:70');
              socket.on('slide', function(slide) {
              $('#slide' + curslide).animate({left:-700}, 400);
              $('#slide' + slide).css('left',700).show().animate({left:0}, 400);
              curslide = slide;
              });
              </script>
              <style>
              #slideshow, .slide { width:700px; height:400px; overflow:hidden; position:relative; }
              .slide { position:absolute; top:0px; left:700px; }
              </style>
              </head>
              <body>
              <div id="slideshow">
              {{~it.slides :url:i}}
              <div id="slide{{=i}}" class="slide"><img src="{{=url}}"></div>
              {{~}}
              </div>
              <button id="next">Next &gt;</button>
              </body>
              </html>


              Copy these two files into a folder, then run



              $ npm install express socket.io dot
              $ node app.js


              and navigate to http://localhost:70 in several different windows, then see the magic.






              share|improve this answer















              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



              var express = require('express')
              , app = express.createServer()
              , io = require('socket.io').listen(app)
              , doT = require('dot')
              , slide = 0
              , slides = [
              'http://placekitten.com/700/400?image=13',
              'http://placekitten.com/700/400?image=14',
              'http://placekitten.com/700/400?image=15',
              'http://placekitten.com/700/400?image=16',
              'http://placekitten.com/700/400?image=1',
              'http://placekitten.com/700/400?image=2',
              'http://placekitten.com/700/400?image=3',
              'http://placekitten.com/700/400?image=4',
              'http://placekitten.com/700/400?image=5',
              'http://placekitten.com/700/400?image=6',
              'http://placekitten.com/700/400?image=7',
              'http://placekitten.com/700/400?image=8',
              'http://placekitten.com/700/400?image=9',
              'http://placekitten.com/700/400?image=10',
              'http://placekitten.com/700/400?image=11',
              'http://placekitten.com/700/400?image=12',
              ];

              app.listen(70); // listen on port 70

              app.register('.html', doT); // use doT to render templates
              app.set('view options', {layout:false}); // keep it simple
              doT.templateSettings.strip=false; // don't strip line endings from template file

              app.get('/', function(req, res) {
              res.render('index.html', { slide: slide, slides: slides });
              });

              app.post('/next', function(req, res) {
              next();
              res.send(204); // No Content
              });

              setInterval(next, 4000); // advance slides every 4 seconds

              function next() {
              if (++slide >= slides.length) slide = 0;
              io.sockets.emit('slide', slide);
              }


              views/index.html



              This file is processed as a doT template.



              <!DOCTYPE html>
              <html>
              <head>
              <title>Synchronized Slideshow</title>
              <script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
              <script src="/socket.io/socket.io.js"></script>
              <script>
              var curslide = {{=it.slide}}; // the slide the server is currently on.

              $(function() {
              $('#slide' + curslide).css('left',0);

              $('#next').click(function() {
              $.post('/next');
              });
              });

              var socket = io.connect('http://localhost:70');
              socket.on('slide', function(slide) {
              $('#slide' + curslide).animate({left:-700}, 400);
              $('#slide' + slide).css('left',700).show().animate({left:0}, 400);
              curslide = slide;
              });
              </script>
              <style>
              #slideshow, .slide { width:700px; height:400px; overflow:hidden; position:relative; }
              .slide { position:absolute; top:0px; left:700px; }
              </style>
              </head>
              <body>
              <div id="slideshow">
              {{~it.slides :url:i}}
              <div id="slide{{=i}}" class="slide"><img src="{{=url}}"></div>
              {{~}}
              </div>
              <button id="next">Next &gt;</button>
              </body>
              </html>


              Copy these two files into a folder, then run



              $ npm install express socket.io dot
              $ node app.js


              and navigate to http://localhost:70 in several different windows, then see the magic.







              share|improve this answer














              share|improve this answer



              share|improve this answer








              edited Jul 2 '12 at 22:07

























              answered May 19 '12 at 4:16









              josh3736josh3736

              103k20175226




              103k20175226













              • Love this answer! Ignoring my question to get to the same objective. I'm going to take this approach and see what I can get out of it!

                – Josh Hunt
                May 20 '12 at 2:27











              • And kudos for the demo link!

                – Josh Hunt
                May 20 '12 at 2:33











              • I got a couple of errors running this with the latest version of Express. Only when I pinned it to version 2.5.10 and reinstalled did it work. Also, I had to run sudo node app.js

                – skube
                Dec 30 '16 at 15:27






              • 1





                Yeah, this is very old and express obviously has many breaking changes between v2 and v4. The need for sudo comes from listening on port 70, change that to something >1024 to fix.

                – josh3736
                Jan 2 '17 at 2:28



















              • Love this answer! Ignoring my question to get to the same objective. I'm going to take this approach and see what I can get out of it!

                – Josh Hunt
                May 20 '12 at 2:27











              • And kudos for the demo link!

                – Josh Hunt
                May 20 '12 at 2:33











              • I got a couple of errors running this with the latest version of Express. Only when I pinned it to version 2.5.10 and reinstalled did it work. Also, I had to run sudo node app.js

                – skube
                Dec 30 '16 at 15:27






              • 1





                Yeah, this is very old and express obviously has many breaking changes between v2 and v4. The need for sudo comes from listening on port 70, change that to something >1024 to fix.

                – josh3736
                Jan 2 '17 at 2:28

















              Love this answer! Ignoring my question to get to the same objective. I'm going to take this approach and see what I can get out of it!

              – Josh Hunt
              May 20 '12 at 2:27





              Love this answer! Ignoring my question to get to the same objective. I'm going to take this approach and see what I can get out of it!

              – Josh Hunt
              May 20 '12 at 2:27













              And kudos for the demo link!

              – Josh Hunt
              May 20 '12 at 2:33





              And kudos for the demo link!

              – Josh Hunt
              May 20 '12 at 2:33













              I got a couple of errors running this with the latest version of Express. Only when I pinned it to version 2.5.10 and reinstalled did it work. Also, I had to run sudo node app.js

              – skube
              Dec 30 '16 at 15:27





              I got a couple of errors running this with the latest version of Express. Only when I pinned it to version 2.5.10 and reinstalled did it work. Also, I had to run sudo node app.js

              – skube
              Dec 30 '16 at 15:27




              1




              1





              Yeah, this is very old and express obviously has many breaking changes between v2 and v4. The need for sudo comes from listening on port 70, change that to something >1024 to fix.

              – josh3736
              Jan 2 '17 at 2:28





              Yeah, this is very old and express obviously has many breaking changes between v2 and v4. The need for sudo comes from listening on port 70, change that to something >1024 to fix.

              – josh3736
              Jan 2 '17 at 2:28













              22














              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:



              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();
              var start = (new Date).getTime();

              r.open('HEAD', document.location, false);
              r.onreadystatechange = function()
              {
              if (r.readyState != 4)
              {
              return;
              }
              var latency = (new Date).getTime() - start;
              var timestring = r.getResponseHeader("DATE");

              // Set the time to the **slightly old** date sent from the
              // server, then adjust it to a good estimate of what the
              // server time is **right now**.
              systemtime = new Date(timestring);
              systemtime.setMilliseconds(systemtime.getMilliseconds() + (latency / 2))
              };
              r.send(null);
              }


              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.






              share|improve this answer


























              • An amazing answer! Pretty sure this is the best solution available, but im going to add a bounty on to see if I can attract some other solutions.

                – Josh Hunt
                May 16 '12 at 8:14






              • 4





                This is how I would do it. The only difference being that I would do a sync call several times (i.e. 10 times) and then use the systemtime from the call with the lowest latency. Indeed, the higher the latency, the more impact you have from the fact that the distribution between from-client-to-server-time and from-server-to-client-time is not exactly 1:1.

                – Willem Mulder
                May 19 '12 at 12:50











              • Is there a better option than dividing response time by 2? In some of my tests the server blocks for awhile but then returns quickly. So maybe the trip time was 200ms, but the time returned is only 20ms off. Does that make sense?

                – jocull
                Jul 23 '13 at 15:27











              • Useful code. It's giving better results than "ServerDate" library. :)

                – xdevnull
                Dec 25 '18 at 20:08
















              22














              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:



              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();
              var start = (new Date).getTime();

              r.open('HEAD', document.location, false);
              r.onreadystatechange = function()
              {
              if (r.readyState != 4)
              {
              return;
              }
              var latency = (new Date).getTime() - start;
              var timestring = r.getResponseHeader("DATE");

              // Set the time to the **slightly old** date sent from the
              // server, then adjust it to a good estimate of what the
              // server time is **right now**.
              systemtime = new Date(timestring);
              systemtime.setMilliseconds(systemtime.getMilliseconds() + (latency / 2))
              };
              r.send(null);
              }


              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.






              share|improve this answer


























              • An amazing answer! Pretty sure this is the best solution available, but im going to add a bounty on to see if I can attract some other solutions.

                – Josh Hunt
                May 16 '12 at 8:14






              • 4





                This is how I would do it. The only difference being that I would do a sync call several times (i.e. 10 times) and then use the systemtime from the call with the lowest latency. Indeed, the higher the latency, the more impact you have from the fact that the distribution between from-client-to-server-time and from-server-to-client-time is not exactly 1:1.

                – Willem Mulder
                May 19 '12 at 12:50











              • Is there a better option than dividing response time by 2? In some of my tests the server blocks for awhile but then returns quickly. So maybe the trip time was 200ms, but the time returned is only 20ms off. Does that make sense?

                – jocull
                Jul 23 '13 at 15:27











              • Useful code. It's giving better results than "ServerDate" library. :)

                – xdevnull
                Dec 25 '18 at 20:08














              22












              22








              22







              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:



              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();
              var start = (new Date).getTime();

              r.open('HEAD', document.location, false);
              r.onreadystatechange = function()
              {
              if (r.readyState != 4)
              {
              return;
              }
              var latency = (new Date).getTime() - start;
              var timestring = r.getResponseHeader("DATE");

              // Set the time to the **slightly old** date sent from the
              // server, then adjust it to a good estimate of what the
              // server time is **right now**.
              systemtime = new Date(timestring);
              systemtime.setMilliseconds(systemtime.getMilliseconds() + (latency / 2))
              };
              r.send(null);
              }


              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.






              share|improve this answer















              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:



              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();
              var start = (new Date).getTime();

              r.open('HEAD', document.location, false);
              r.onreadystatechange = function()
              {
              if (r.readyState != 4)
              {
              return;
              }
              var latency = (new Date).getTime() - start;
              var timestring = r.getResponseHeader("DATE");

              // Set the time to the **slightly old** date sent from the
              // server, then adjust it to a good estimate of what the
              // server time is **right now**.
              systemtime = new Date(timestring);
              systemtime.setMilliseconds(systemtime.getMilliseconds() + (latency / 2))
              };
              r.send(null);
              }


              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.







              share|improve this answer














              share|improve this answer



              share|improve this answer








              edited May 14 '12 at 22:55









              Josh Hunt

              4,182236792




              4,182236792










              answered May 14 '12 at 15:17









              MikeWyattMikeWyatt

              4,94194067




              4,94194067













              • An amazing answer! Pretty sure this is the best solution available, but im going to add a bounty on to see if I can attract some other solutions.

                – Josh Hunt
                May 16 '12 at 8:14






              • 4





                This is how I would do it. The only difference being that I would do a sync call several times (i.e. 10 times) and then use the systemtime from the call with the lowest latency. Indeed, the higher the latency, the more impact you have from the fact that the distribution between from-client-to-server-time and from-server-to-client-time is not exactly 1:1.

                – Willem Mulder
                May 19 '12 at 12:50











              • Is there a better option than dividing response time by 2? In some of my tests the server blocks for awhile but then returns quickly. So maybe the trip time was 200ms, but the time returned is only 20ms off. Does that make sense?

                – jocull
                Jul 23 '13 at 15:27











              • Useful code. It's giving better results than "ServerDate" library. :)

                – xdevnull
                Dec 25 '18 at 20:08



















              • An amazing answer! Pretty sure this is the best solution available, but im going to add a bounty on to see if I can attract some other solutions.

                – Josh Hunt
                May 16 '12 at 8:14






              • 4





                This is how I would do it. The only difference being that I would do a sync call several times (i.e. 10 times) and then use the systemtime from the call with the lowest latency. Indeed, the higher the latency, the more impact you have from the fact that the distribution between from-client-to-server-time and from-server-to-client-time is not exactly 1:1.

                – Willem Mulder
                May 19 '12 at 12:50











              • Is there a better option than dividing response time by 2? In some of my tests the server blocks for awhile but then returns quickly. So maybe the trip time was 200ms, but the time returned is only 20ms off. Does that make sense?

                – jocull
                Jul 23 '13 at 15:27











              • Useful code. It's giving better results than "ServerDate" library. :)

                – xdevnull
                Dec 25 '18 at 20:08

















              An amazing answer! Pretty sure this is the best solution available, but im going to add a bounty on to see if I can attract some other solutions.

              – Josh Hunt
              May 16 '12 at 8:14





              An amazing answer! Pretty sure this is the best solution available, but im going to add a bounty on to see if I can attract some other solutions.

              – Josh Hunt
              May 16 '12 at 8:14




              4




              4





              This is how I would do it. The only difference being that I would do a sync call several times (i.e. 10 times) and then use the systemtime from the call with the lowest latency. Indeed, the higher the latency, the more impact you have from the fact that the distribution between from-client-to-server-time and from-server-to-client-time is not exactly 1:1.

              – Willem Mulder
              May 19 '12 at 12:50





              This is how I would do it. The only difference being that I would do a sync call several times (i.e. 10 times) and then use the systemtime from the call with the lowest latency. Indeed, the higher the latency, the more impact you have from the fact that the distribution between from-client-to-server-time and from-server-to-client-time is not exactly 1:1.

              – Willem Mulder
              May 19 '12 at 12:50













              Is there a better option than dividing response time by 2? In some of my tests the server blocks for awhile but then returns quickly. So maybe the trip time was 200ms, but the time returned is only 20ms off. Does that make sense?

              – jocull
              Jul 23 '13 at 15:27





              Is there a better option than dividing response time by 2? In some of my tests the server blocks for awhile but then returns quickly. So maybe the trip time was 200ms, but the time returned is only 20ms off. Does that make sense?

              – jocull
              Jul 23 '13 at 15:27













              Useful code. It's giving better results than "ServerDate" library. :)

              – xdevnull
              Dec 25 '18 at 20:08





              Useful code. It's giving better results than "ServerDate" library. :)

              – xdevnull
              Dec 25 '18 at 20:08











              11














              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 the Date function or one of its
              instances, e.g.:



              > ServerDate()
              "Mon Aug 13 2012 20:26:34 GMT-0300 (ART)"

              > ServerDate.now()
              1344900478753

              > ServerDate.getMilliseconds()
              22


              There is also a new method to get the precision of ServerDate's estimate of the
              server's clock (in milliseconds):



              > ServerDate.toLocaleString() + " ± " + ServerDate.getPrecision() + " ms"
              "Tue Aug 14 01:01:49 2012 ± 108 ms"


              You can see the difference between the server's clock and the browsers clock, in milliseconds:



              > ServerDate - new Date()
              39





              share|improve this answer






























                11














                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 the Date function or one of its
                instances, e.g.:



                > ServerDate()
                "Mon Aug 13 2012 20:26:34 GMT-0300 (ART)"

                > ServerDate.now()
                1344900478753

                > ServerDate.getMilliseconds()
                22


                There is also a new method to get the precision of ServerDate's estimate of the
                server's clock (in milliseconds):



                > ServerDate.toLocaleString() + " ± " + ServerDate.getPrecision() + " ms"
                "Tue Aug 14 01:01:49 2012 ± 108 ms"


                You can see the difference between the server's clock and the browsers clock, in milliseconds:



                > ServerDate - new Date()
                39





                share|improve this answer




























                  11












                  11








                  11







                  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 the Date function or one of its
                  instances, e.g.:



                  > ServerDate()
                  "Mon Aug 13 2012 20:26:34 GMT-0300 (ART)"

                  > ServerDate.now()
                  1344900478753

                  > ServerDate.getMilliseconds()
                  22


                  There is also a new method to get the precision of ServerDate's estimate of the
                  server's clock (in milliseconds):



                  > ServerDate.toLocaleString() + " ± " + ServerDate.getPrecision() + " ms"
                  "Tue Aug 14 01:01:49 2012 ± 108 ms"


                  You can see the difference between the server's clock and the browsers clock, in milliseconds:



                  > ServerDate - new Date()
                  39





                  share|improve this answer















                  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 the Date function or one of its
                  instances, e.g.:



                  > ServerDate()
                  "Mon Aug 13 2012 20:26:34 GMT-0300 (ART)"

                  > ServerDate.now()
                  1344900478753

                  > ServerDate.getMilliseconds()
                  22


                  There is also a new method to get the precision of ServerDate's estimate of the
                  server's clock (in milliseconds):



                  > ServerDate.toLocaleString() + " ± " + ServerDate.getPrecision() + " ms"
                  "Tue Aug 14 01:01:49 2012 ± 108 ms"


                  You can see the difference between the server's clock and the browsers clock, in milliseconds:



                  > ServerDate - new Date()
                  39






                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited Dec 11 '13 at 19:32

























                  answered Aug 14 '12 at 15:57









                  David BraunDavid Braun

                  3,01812337




                  3,01812337























                      0














                      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").






                      share|improve this answer



















                      • 1





                        That's exactly how this is functioning. The page waits until the correct time before performing an action to ensure it is syncd across devices. The problem comes down to the fact that I have two iPads next to each other which are set to sync time with time servers, yet are 1 second apart.

                        – Josh Hunt
                        May 15 '12 at 11:20











                      • So you want to implement a time server in javascript, to sync "custom system times"?

                        – Bergi
                        May 15 '12 at 11:25








                      • 2





                        @Bergi, you're erroneously assuming that the client's clock matches the clock on the server. They are practically guaranteed to be different, probably by multiple seconds or minutes. Adjusting for latency isn't perfect, but it will get you pretty close. In the worst case, you'll be off by the full round-trip time, if one of the trips was instantaneous.

                        – MikeWyatt
                        May 16 '12 at 3:47
















                      0














                      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").






                      share|improve this answer



















                      • 1





                        That's exactly how this is functioning. The page waits until the correct time before performing an action to ensure it is syncd across devices. The problem comes down to the fact that I have two iPads next to each other which are set to sync time with time servers, yet are 1 second apart.

                        – Josh Hunt
                        May 15 '12 at 11:20











                      • So you want to implement a time server in javascript, to sync "custom system times"?

                        – Bergi
                        May 15 '12 at 11:25








                      • 2





                        @Bergi, you're erroneously assuming that the client's clock matches the clock on the server. They are practically guaranteed to be different, probably by multiple seconds or minutes. Adjusting for latency isn't perfect, but it will get you pretty close. In the worst case, you'll be off by the full round-trip time, if one of the trips was instantaneous.

                        – MikeWyatt
                        May 16 '12 at 3:47














                      0












                      0








                      0







                      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").






                      share|improve this answer













                      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").







                      share|improve this answer












                      share|improve this answer



                      share|improve this answer










                      answered May 14 '12 at 23:14









                      BergiBergi

                      369k58550878




                      369k58550878








                      • 1





                        That's exactly how this is functioning. The page waits until the correct time before performing an action to ensure it is syncd across devices. The problem comes down to the fact that I have two iPads next to each other which are set to sync time with time servers, yet are 1 second apart.

                        – Josh Hunt
                        May 15 '12 at 11:20











                      • So you want to implement a time server in javascript, to sync "custom system times"?

                        – Bergi
                        May 15 '12 at 11:25








                      • 2





                        @Bergi, you're erroneously assuming that the client's clock matches the clock on the server. They are practically guaranteed to be different, probably by multiple seconds or minutes. Adjusting for latency isn't perfect, but it will get you pretty close. In the worst case, you'll be off by the full round-trip time, if one of the trips was instantaneous.

                        – MikeWyatt
                        May 16 '12 at 3:47














                      • 1





                        That's exactly how this is functioning. The page waits until the correct time before performing an action to ensure it is syncd across devices. The problem comes down to the fact that I have two iPads next to each other which are set to sync time with time servers, yet are 1 second apart.

                        – Josh Hunt
                        May 15 '12 at 11:20











                      • So you want to implement a time server in javascript, to sync "custom system times"?

                        – Bergi
                        May 15 '12 at 11:25








                      • 2





                        @Bergi, you're erroneously assuming that the client's clock matches the clock on the server. They are practically guaranteed to be different, probably by multiple seconds or minutes. Adjusting for latency isn't perfect, but it will get you pretty close. In the worst case, you'll be off by the full round-trip time, if one of the trips was instantaneous.

                        – MikeWyatt
                        May 16 '12 at 3:47








                      1




                      1





                      That's exactly how this is functioning. The page waits until the correct time before performing an action to ensure it is syncd across devices. The problem comes down to the fact that I have two iPads next to each other which are set to sync time with time servers, yet are 1 second apart.

                      – Josh Hunt
                      May 15 '12 at 11:20





                      That's exactly how this is functioning. The page waits until the correct time before performing an action to ensure it is syncd across devices. The problem comes down to the fact that I have two iPads next to each other which are set to sync time with time servers, yet are 1 second apart.

                      – Josh Hunt
                      May 15 '12 at 11:20













                      So you want to implement a time server in javascript, to sync "custom system times"?

                      – Bergi
                      May 15 '12 at 11:25







                      So you want to implement a time server in javascript, to sync "custom system times"?

                      – Bergi
                      May 15 '12 at 11:25






                      2




                      2





                      @Bergi, you're erroneously assuming that the client's clock matches the clock on the server. They are practically guaranteed to be different, probably by multiple seconds or minutes. Adjusting for latency isn't perfect, but it will get you pretty close. In the worst case, you'll be off by the full round-trip time, if one of the trips was instantaneous.

                      – MikeWyatt
                      May 16 '12 at 3:47





                      @Bergi, you're erroneously assuming that the client's clock matches the clock on the server. They are practically guaranteed to be different, probably by multiple seconds or minutes. Adjusting for latency isn't perfect, but it will get you pretty close. In the worst case, you'll be off by the full round-trip time, if one of the trips was instantaneous.

                      – MikeWyatt
                      May 16 '12 at 3:47











                      0














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






                      share|improve this answer




























                        0














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






                        share|improve this answer


























                          0












                          0








                          0







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






                          share|improve this answer













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







                          share|improve this answer












                          share|improve this answer



                          share|improve this answer










                          answered May 19 '12 at 12:20









                          ChrisChris

                          1,50532745




                          1,50532745






























                              draft saved

                              draft discarded




















































                              Thanks for contributing an answer to Stack Overflow!


                              • Please be sure to answer the question. Provide details and share your research!

                              But avoid



                              • Asking for help, clarification, or responding to other answers.

                              • Making statements based on opinion; back them up with references or personal experience.


                              To learn more, see our tips on writing great answers.




                              draft saved


                              draft discarded














                              StackExchange.ready(
                              function () {
                              StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f10585910%2fsync-js-time-between-multiple-devices%23new-answer', 'question_page');
                              }
                              );

                              Post as a guest















                              Required, but never shown





















































                              Required, but never shown














                              Required, but never shown












                              Required, but never shown







                              Required, but never shown

































                              Required, but never shown














                              Required, but never shown












                              Required, but never shown







                              Required, but never shown







                              Popular posts from this blog

                              mysqli_query(): Empty query in /home/lucindabrummitt/public_html/blog/wp-includes/wp-db.php on line 1924

                              How to change which sound is reproduced for terminal bell?

                              Can I use Tabulator js library in my java Spring + Thymeleaf project?