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.
From my tests, and from searching to find out more about the problem, my best guess is that css animations may be using a different physical clock from the one used to stream audio. If so perhaps the answer to this is that it can't be done, but am asking in case I am missing anything.
It is for my online metronome here.
It is able to plays notes reasonably accurately in response to an event listener for the css animationiteration event. The eventlistener is set up using e.g.
x.addEventListener("animationstart",playSoundBall2);
See here.
However if I try to synchronize the bounce with the sample precise timing of the AudioContext method that's when I run into problems.
What I do is to use the first css callback just to record the audio context time for the css elapsed time of 0. Then I play the notes using the likes of:
oscillator.start(desired_start_time);
You can try it out with the option on the page: "Schedule notes in advance for sample-precise timing of the audio" on the page here.
You can check how much it drifts by switching on "Add debug info to extra info" on the same page.
On my development machine it works fine with Firefox. But on Edge and Chrome it drifts away from the bounce. And not in a steady way. Can be fine for several minutes and then the bounce starts to slow down relative to the audio stream.
It is not a problem with browser activity - if I move the browser around and try to interrupt the animation the worst that happens is that it may drop notes and if the browser isn't active it is liable to drop notes. But the ones it plays are exactly in time.
My best guess so far, is that it might be that the browser is using the system time, while the audiocontext play method is scheduling it at a precise point in a continuous audio stream. Those may well be using different hardware clocks, from online searches for the problem.
Firefox may for some reason be using the same hardware clock, maybe just on my development machine.
If this is correct, it rather looks as if there is no way to guarantee to precisely synchronize html audio played using AudioContext with css animations.
If that is so I would also think you probably can't guarantee to synchronize it with any javascript animations as it would depend on which clocks the browser uses for the animations, and how that relates to whatever clock is used for streaming audio.
But can this really be the case? What do animators do who need to synchronize sound with animations for long periods of time? Or do they only ever synchronize them for a few minutes at a time?
I wouldn't have noticed if it weren't that the metronome naturally is used for long periods at a time. It can get so bad that the click is several seconds out from the bounce after just two or three minutes.
At other times - well while writing this I've had the metronome going for ten minutes in my Windows 10 app and it has drifted, but only by 20-30 ms relative to the bounce. So it is very irregular, so you can't hope to solve this by adding in some fixed speed up or slow down to get them in time with each other.
I am writing this just in case there is a way to do this in javascript, anything I'm missing. I'm also interested to know if it makes any difference if I use other methods of animation. I can't see how one could use the audio context clock directly for animation as you can only schedule notes in the audio stream, can't schedule a callback at a particular exact time in the future according to the audio stream.
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.
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.
I need to be able to benchmark a particular build of a webkit-based browser and am measuring the length of time it takes to do certain stuff like DOM manipulation, memory limits etc.
I have a test below which records the length of time it takes to simultaneously load in 10 fairly heavy PNG graphics. In code, I need to be able to time how long it takes for the load to finish. I have tried setting
the onLoad function on the dynamic Image object to produce a time in ms. However, as shown in the cap below it is giving an inaccurate reading because the reading it gives is a tiny amount due to it only recording the data transfer part of the load and then there is a considerable (3000+ms) delay for when the images are viewable - looped in blue, this is the browser reflow cycle.
Is there some event in webkit I can use to record when the browser has finished a reflow so that I can benchmark this? I have to be able to record the time in milliseconds in code because the build of webkit I am testing has no developer tools. I am able to observe the difference in Chrome ok but the performance between the two builds differs drastically and I need to be able to quantify it accurately for comparison.
If you are using jQuery, you could try recording the time between document ready and window load, that would give you an approximation.
(function(){
var start, end;
$(document).ready(function(){
start = new Date()
});
$(window).load(function(){
end = new Date();
console.log(end.getTime() - start.getTime());
});
}());
Edit:
Have you taken a look at the Browserscope reflow timer? Basically it checks to see how long it takes for the browser to return control to the JavaScript engine after changes to the dom. According the the page it should work in any browser, although I haven't tested it personally. Perhaps you could adapt the code run during the tests to time the reflow in your page.
Also, you might want to have a look at CSS Stress Test. The bookmarklet is really great for page performance testing. http://andy.edinborough.org/CSS-Stress-Testing-and-Performance-Profiling
How about setting the PNG as a div background-image and running the stress test, it should enable/disable the image multiple times with timings.