1

I'm running into some strange error with the Date.now() function in JS.

Background Info: I'm developing a webApp that sends and receives packets to/from a server. All my incoming packets are marked with a timestamp, generated by Date.now(). Among these packets is data, that is printed into a line chart. So I get a value on the y axis and the timestamp on the x axis. So far so good.

Letting the app run has shown me some strange behaviour -> My line chart sometimes draws data points back in the past, right before already present data points! While checking the timestamps of these points i saw, that my chart does everything right, but the timestamps are wrong.

So I wrote a little test script, to collect some more evidence:

var i = 0;
var ts = [Date.now()];

setInterval(function () {

    ts.push(Date.now());

    console.info("checking next timestamp ...");

    if (ts[i] > ts[i+1]) {

        console.error("old timestamp (" + ts[i] + ") is BIGGER than current timestamp (" + ts[i+1] + ")!");
    }

    i++;

}, 100);

Running this over a few minutes prints me one error:

Chrome DevTools Console Error 1

Way later i get another one, and so on.

Chrome DevTools Console Error 2

For this test i chose 100ms interval time to check many timestamps. But my App has an update interval of maybe 5s and still there arrives this error sometimes. Not as often as with 100ms, but it's there :(

Has anyone else seen this behaviour before? Am I doing something wrong here?

BTW: The packets in my App come in one by one, so it's impossible that the order of the packets is mixed up or sth.

Fidel90
  • 1,828
  • 6
  • 27
  • 63
  • I can't reproduce that problem in Chrome, Firefox and even in IE. – Cerbrus Aug 27 '14 at 10:16
  • @Cerbrus: I'm using Chrome as well and run into this error after some minutes. Sometimes it happens faster, sometimes it takes longer... – Fidel90 Aug 27 '14 at 10:17
  • I'll leave it running during lunch – Cerbrus Aug 27 '14 at 10:19
  • I just tested this script by executing it in the console (without my app) and after the first 500 checks i get an error... (1409134821738 > 1409134821672)...PS: Next error after 1200 checks :( – Fidel90 Aug 27 '14 at 10:22
  • @AwalGarg: Thanks for your feedback. No, my CPU has nearly no load and memory is kind of empty. I'm checking with FF atm and dont encounter any error after over 9000 checks. Parallel in Chrome I have 11 errors in the same time... – Fidel90 Aug 27 '14 at 10:41
  • Well, 4200 checks is my maximum error free count that I achieve with Chrome. FF still runs at 17000 without a single error. Am I the only one with these problems in Chrome? Could the VM where my Windows 7 is running in influence this behaviour? I'm running Chrome 36.0.1985.143 m (what does "m" mean?). – Fidel90 Aug 27 '14 at 10:56
  • Just updated Chrome to 37.0.2062.94 ... same behaviour :( – Fidel90 Aug 27 '14 at 11:06
  • 1
    30000 checks later, no issues. – Cerbrus Aug 27 '14 at 11:10
  • Interesting. I'm checking IE and Chromium right now. – Fidel90 Aug 27 '14 at 11:16
  • 1
    Both seem to work fine after 8-9000 checks. So what's the issue with chrome here? Should I open a ticket at ChromeDev as I am the only one with this problem? – Fidel90 Aug 27 '14 at 11:31
  • 1
    You could try a fresh chrome install. Might be some kind of memory issue? Otherwise, a ticket would work. – Cerbrus Aug 27 '14 at 11:49
  • Reinstalling did not help...anyway, thanks for your help everybody! :) – Fidel90 Aug 27 '14 at 12:07
  • 1
    It does sound a lot like VM clock drift. If the errors are recurring at regular intervals of some minutes, this could be when the VM clock is resynced with the hardware clock. – 1983 Aug 27 '14 at 12:12
  • @mintsauce: But why don't FF and IE (both in VM) show this issue? – Fidel90 Aug 27 '14 at 12:20
  • I have filed this issue: https://code.google.com/p/chromium/issues/detail?id=408077 – Fidel90 Aug 27 '14 at 12:21
  • Maybe FF and IE use monotonic timers which aren't affected by system clock changes. It might be worth a little research. – 1983 Aug 27 '14 at 12:21
  • See if this question helps: http://stackoverflow.com/questions/7272395/monotonically-increasing-time-in-javascript – 1983 Aug 27 '14 at 12:34
  • I'm going to play around with window.performance.now() to see if it fits my needs: https://developer.mozilla.org/en-US/docs/Web/API/Performance – Fidel90 Aug 27 '14 at 13:13

1 Answers1

0

Well, as I have taken a look onto the Performance API yesterday, I think this is the way to go. I implemented it in my application as follows:

Everytime when I receive an input packet from my server I give them a timestamp. Until now I had realised this by Date.now() but this seems to be inconsistent as the OS or the VM (or both) recalculate their current time from time to time.

So now I calculate my own timestamp. For this I have to read the timestamp from when my application started. The performance API gives me this value by

var startTS = window.performance.timing.navigationStart; //returns a timestamp in ms

So this is a value available everywhere in my app since it exists in the window namespace and does not need a global variable made by myself. Very nice.

Now, to get the current timestamp, I have to add a time value that indicates how long my application is running since startTS. To get this we just use:

var timeSinceStartup = window.performance.now(); //returns sth. like 1337.9836718 (ms with fractional part)

If needed, one can round this value as the fractional part might not be needed:

var rounded = (timeSinceStartup + 0.5) | 0; //same as but faster than Math.round(timeSinceStartup);

Well, the rest is easy. We just have to add those values (as both are milliseconds) and voila:

var currentTS = startTS + timeSinceStartup;

I have updated the little code snippet from my question to test this:

var i = 0;
var start = window.performance.timing.navigationStart;
var ts = [start + window.performance.now()];

setInterval(function () {

    ts.push(start + window.performance.now());

    console.info("checking next timestamp ...");

    if (ts[i] > ts[i+1]) {

        console.error("old timestamp (" + ts[i] + ") is BIGGER than current timestamp (" + ts[i+1] + ")!");
    }

    i++;

}, 100);

Chrome is running this test at the moment (in VM) and it looks like everything is just fine (17500 checks without an error). I would have wondered if sth. else would happen, as we just add a constant with a monoton rising value ;)

Only drawback of this solution seems to be the browser support. As of now every modern browser but Safari support this. As my app is developed to run only on modern browsers this is ok for me, but the lack of Safari is bad.

http://caniuse.com/#feat=high-resolution-time

I will have to take a look into crossbrowser solutions/polyfills/Frameworks or sth. Thanks everybody for your help. Anyway I'm still curious if there might be a solution for Date.now() in Chrome, as FF and IE had no problems with using it.

https://code.google.com/p/chromium/issues/detail?id=408077

EDIT

This seems to be a good polyfill for a missing Performance API: https://gist.github.com/paulirish/5438650

Ofcourse it falls back to Date.now(), so in browsers that don't support the API I might run into the same problem as before. For this case I just keep checking my timestamps in the app and if a timing error occurs I'm going to handle it silently (e.g. don't draw it to the chart, instead wait for the next value).

So long...

Fidel90
  • 1,828
  • 6
  • 27
  • 63