How accurate is setTimeout/setInterval in Node.js and the browser? - javascript

I'm setting a timer in Node.js that waits for 3 hours to emit an event, once that time is reached it emits the event to all browsers that are listening.
The browsers gathers the information that such event before it happens and then calculates the time remaining ticking a countdown every 1 second, and expecting that when the clock reaches 0 the event will be triggered.
So one is using setTimeout (Node.js) and the other is using setInterval (browser) counting per second (countdown).
can I be sure that?
By the time the countdown reaches 0, the event will be triggered with an error range of around 1 to 2 seconds. (browser).
That the Node.js setTimeout is accurate enough to be called with a less than 1 second error range.
I've read about timers being 500ms to even 1000ms innacurate, which is fine for my needs, but I have never heard of them being used for this much time as I want to do.
Are they accurate enough or should I use a different solution? especially in the Node.js side which has to be the most accurate of them all.
Alternatives are to make a interval in Node.js that runs around 4 times per second, calculates the Date milliseconds, and checks if there are events that it needs to call from a list of events.
In the browser is to set the interval so that it calculates the date ms with every callback to try to keep the time synchronized.

The accuracy of the timer will be dependent upon how "busy" the event loop is at the time of the timeout.
It should be good enough if you wanted something like:
setTimeout(done, THREE_HOURS_IN_MS);
If your event loop is blocking for any length of time you have other problems.
But if you are sampling four times a second as part of the countdown, then I would expect a large inaccuracy to accrue.
So you may need to keep the two activities (sampling and countdown) separate, or maintain the elapsed time manually.
Note that when your web app does not have focus, the accuracy of timers degrades.

Related

JavaScript: Stop HTML5 video exactly at currentTime=x

I want to play a HTML5 video in segments of x seconds. For example, start at t=0 and pause at t=x, then start at t=x and pause at t=2x. The problem is that the updates I receive with ontimeupdate don't match my intervals. There is one update short before the intended stop time and one update shortly after. I could just stop the video whenever currentTime >= x, but the problem here is that this stop point would fall into the new interval. The requirement for this task is to stop at the end of a given interval.
If stopping exactly at a given time is not possible, is there any way to determine the closest possible stop time before that time? That would still be better than stopping too late. I checked the deltas of currentTime (time between each ontimeupdate call), but these are not constant. I read somewhere else that the browser adapts this rate based on some optimization criterions, so that is probably hard to compute.
Background for this question is a tool that I want to develop. The user is shown a video and he is required to answer some questions for each x second interval of this video.
Unfortunately the timeupdate event doesn't provide a lot of granularity. You can read this answer for more information.
One alternative is to set up an interval manually with setInterval, and on each interval check the time passed with Date.now() since the last time that the timeupdate was updated (also using Date.now() and saving that value somewhere).
That would allow knowing the milliseconds from then, although it would need to handle cases like pausing the video and clearing the interval when necessary to avoid memory leaks with clearTimeout.

indexedDB.open() does not deliver the success event

People usually do this:
var DBOpenRequest = window.indexedDB.open("toDoList");
DBOpenRequest.onsuccess = function(event) {//Good};
If the second line of the code is not executed in a timely manner, the onsuccess will miss the event.
Well, the problem does not happen often because the delay between those two lines is usually very short. But, still, the outcome of those two lines is not deterministic. On my machine, if I simulate 270 ms delay between those two lines, the event will be missed. I think the current signature of the open() is inadequate.
The correct asynchronous design pattern is to set the event handler first, then to start the actual asynchronous operation. The open() function should take a callback as an argument.
Any comments?
Updated questions:
async function test(delay)
{
var req = indexedDB.open("test");
//Simulate a delay
await new Promise(resolve => setTimeout(resolve, delay));
req.onsuccess = function (evt) {console.log("Good");};
}
test(1);
If the delay is 1 ms, the "Good" will be logged. If the delay is 1000 ms like test(1000), the "Good" will not be logged, meaning the event handler is not called.
Review the basics of the EventListener design pattern. indexedDB basically adopts the same pattern used throughout several Javascript components such as DOM elements and XMLHttpRequest, and assumes your familiarity with the pattern.
Review how JavaScript's event loop operates because it is important to understand asynchronous code.
Whether you bind a listener function before or after an event is dispatched is irrelevant within the context of asynchronous code. Basically, the bind that you state occurs later, because it is written in a statement on the following line of code, does not actually occur later. Regardless of where it the line is written (barring some pedantic exceptions), it occurs within the same tick of the event loop as the previous line, the call to open. The event does not fire until, at the earliest, the next event loop epoch, which will always be after the binding occurred in the previous event loop epoch. Always. Guaranteed.
The time delay between the calling of the code that does something that causes an event, and the eventual occurrence and reception of that event, is irrelevant. This delay is related to many other things, like how powerful your machine is, how many resources are available to your pc, how busy your script is trying to do other things, possibly even how much junk you have loaded into the dom, because any of those things could contribute into extending the lifetime of the current epoch of the event loop. The delay is implemented as an indefinite wait period. It is basically coded as "occur in some later event loop epoch". This could be 1 nanosecond later, it could be 10000 seconds later, the amount of the delay is irrelevant. The only relevant concern is that the event triggers in the next event loop epoch, which is some time after everything else occurred in the prior event loop epoch.
The second line will always be executed in a timely manner, because the basic criteria for timely here is simply "in the same epoch of the event loop", and here, timely, again, could mean any amount of time.
The outcome is deterministic. Stop thinking of time ticks as an amount of milliseconds elapsed or something like that. Instead think of time as ticks of an event loop. Each tick can take a variable amount of time. Ticks are ordered. Ticks are serial. Tick 2 will occur after Tick 1. Tick 3 will occur after Tick 2. Etc. This is therefore deterministic with regard to execution order, accounting for variable amounts of time per tick. A tick is just a period of time, and despite the periods perhaps having variable amounts, you can still state claims such as the fact that some period occurs before or after some other period. Also, no two periods overlap, ever (not true concurrency, not actually multi-threaded, not strictly interleaved).
I dunno, imagine a stopwatch, or an old wristwatch, or a clock on the wall. The hand travels around the face of the watch. Let's pretend it takes 1 second for the hand to travel from the starting point, all the way around 360 degrees, and return to the starting point. Each roundtrip, let's call it an epoch, or a tick. We can then count how many roundtrips occur, by counting the number of passes back across the starting point. Basically the number of epochs, basically there is cardinality.
Now imagine two watches. The first watch still takes a full second to travel all the way around. The second watch, however, let's pretend, it is an old slow watch, takes 2 seconds to travel all the way around. Half the frequency. Now, the thing is, even though the timing is different between the two watches, we still can make claims like "watch 1 did 10 roundtrips" and "watch 2 did 5 roundtrips".
Now, take it further. Let's take a watch, and introduce random external factors. There are cosmic rays that introduce sporadic gravitational effects on the speed of the hand as it rotates around the watch face. So, some roundtrips hit little speed bumps, and take longer. So we get a distribution of roundtrip times. We still have an average round trip time, but not a constant round trip time. In roundtrip 1, our watch may make the trip in 1 second. In round 2, it may take 2.5 seconds. In round 3, it may take 1 nanosecond. The time is variable. But, this variability does not prevent us from stating things like "well there were 3 round trips when we observed it", and "well the second round trip occurred after the first one", and "no roundtrip travel ever occurred at the same time as another (round trip 1 and 2 and 3 have no overlap)".
These roundtrips are the epochs of the javascript event loop. Your bindings all take place in roundtrip #1. The event that occurs as result of opening indexedDB never takes place in roundtrip #1, no matter where you write it, in whatever order you write it, etc. The event always occurs in either roundtrip #2, or #3, or basically any epoch after roundtrip #1. Even if the event is magically technically 'ready' in #1, it still will not be exposed until #2 or later.
Because the call to open and the binding of the open listener both occur in the first epoch, it is irrelevant to talk about whether the listener is bound before or after the call to open. Because those all happen in #1, and the open event doesn't happen until at the earliest #2.

How to measure latency between interaction and mousedown event in JavaScript?

Is there a way to measure the latency between when I press my mouse button and when a defined onmousedown function fires?
Or, are there current statistics available about this latency?
I assume these two events are not simultaneous, and vary by browser.
My only approach so far has been to create multiple onmousedown events and measure the time difference between them using Date. I found up to a 6ms difference between them.
I am working on audio applications which are time-sensitive (to milliseconds).
Any help is great, thanks!
You are likely looking for the difference between Event.timeStamp and the current timestamp, Date.now(). They both return the elapsed time since the epoch in milliseconds:
JavaScript
document.getElementById("mydiv").addEventListener('click', function (e) {
// in milliseconds
var latency = Date.now() - e.timeStamp;
});
Working example on JSFiddle.
By subtracting the former from the latter - as you can see in the included snippet - you can measure latency.
Unfortunately, the event timeStamp is not the actual hardware moment the mouse was clicked, but rather when the browser received the click event from your OS. This, however, always happens before the event handler is called, and should have negligible latency.
Regarding the linked fiddle, the time differences for me are below 1ms most of the time; I've occasionally managed to achieve values above 10ms with merciless button smashing and page reloading, but it's not common. Of course, if you do more computationally intensive tasks in your event handlers, the difference can easily climb, in which case latency compensation can quickly become an essential part.

animation callback architecture and time measuring when using HTLM5 Canvas?

I'm doing some animation with Canvas now, and will be preparing a system for the artists to use to make interactive animations. I'll be using my own timeline as the scenes will be created from some declarative non-js input. My question is: what's the right way to handle the per frame callback and time measurement? In audio (my real-time background), the rule is that there should be only only one master callback method called by the audio system, and any other objects register with it somehow. And all time calculations are done by counting sample ticks of this callback so there is one and only one true clock source (no asking the system clock for anything, just count samples). I assumed this is what I should do in my canvas app but I'm seeing examples in books and sites where multiple objects use requestAnimationFrame, and then check the frame rate by using date objects to measure elapsed time. Am I off base in thinking one master callback is still the most elegant way to go? And can I rely on measuring time in frame ticks assuming I'm getting really 60fps if using requestAnimationFrame?
Your instinct is valid...route all your animation through one requestAnimationFrame loop to keep your animations well coordinated.
The current version of requestAnimationFrame in modern browsers automatically receives a highly accurate timestamp parameter based on the performance object. That timestamp is accurate to 1/1000th of a millisecond.
You cannot rely on counting the number of calls ("ticks") to the animation loop. The loop will be deferred if the prior loop's animation code has not completed or if the system is busy. Therefore, you are not guaranteed 60fps. You are guaranteed the browsers best efforts to get you 60fps.
Bottom line: requestAnimationFrame is not guarenteed to be called at 60fps intervals so you are left with 2 basic animation alternatives:
Use the timestamp to calculate an elaped time and position your objects based on elapsed time.
Increment a counter with each call to the animation loop and postion your objects based on the counter.

Inconsistent timeouts in javascript with setTimeout?

I am making a game. The game has 1 main loops:
//draws a new frame and game logic
function draw()
{
player.gameTick();
game.gameTick();
lastTime=newTime;
background.draw(ctx);
player.draw(ctx);
enemies.draw(ctx);
setTimeout(draw,50);
}
Normally this operates fine, and I get 20fps reported to #console. Once in a while, however, the fps spikes up to >125. (meaning draw is being called less than 50 milliseconds after the previous call). When this happens, the game starts to lag for a couple of seconds, and then the fps goes back down. (that's also counter intuitive, why does HIGHER fps cause lag?)
Anyway, does anyone know why this is the case?
Yes I have tried setInterval() also, and the same thing happens. =/
JavaScript is single threaded. If you're scheduling two timeouts for 50 ms independently, there's a chance that they eventually collide, or come close to it, and cause an odd processing blockage for a second before they sort themselves out and can space out again. You should probably consolidate the code and create a single main loop that calls the other two functions. That way you can ensure that they both process once each per 50 ms.
Your flow looks something like this:
Process1() -> takes some amount of time, hopefully less than 50ms, but guaranteed to be > 0ms.
Process1 sets a timeout for itself 50ms in the future. The 2nd run of Process1 will occur more than 50ms after it started the 1st time.
Process2() -> takes some amount of time, greater than 0ms. Same as Process1.
Process2 sets a timeout for itself. Same rules apply. The 2nd run of Process2 will occur more than 50ms after it started the 1st time.
If, theoretically, Process1 takes 5ms and Process2 takes 7ms, every 7 runs of Process1 or 5 runs Process2 will cause the next timeout set for 50ms in the future to correspond exactly with the scheduled time for the next run of the other function. This type of collision will cause inconsistent behavior when the interpreter, which can only do one thing at a time, is asked to handle multiple events concurrently.
-- Edits for your revisions to the question --
You're still setting two independent timeouts for 50ms in the future. There's still no way to prevent these from colliding, and I'm still not entirely certain why you're approaching it this way. You should have something like this:
function mainLoop() {
player.tick();
game.tick();
background.draw();
players.draw();
enemies.draw();
setTimeout(mainLoop, 50);
}
mainLoop()
Note the absence of repetitive setTimeout calls. Everything can happen in one go. You're creating collisions in both versions of your demonstrated code.
This problem was caused by browser javascript timer throttling. I noticed the problem was exacerbated when I have many tabs open or when I switch between tabs. Chrome had less of an issue, most likely due to tabs being in isolated processes.
Firefox 7 seems to have fixed this problem for FF.

Categories