Ilya Markov
Script programmer at iRidium mobile
The image to the post is a painting by Salvador Dali “Time flows”. The choice is not a chance one and essentially metaphorical.
In JS programming time may flow in a way, different from what we suppose it to. JavaScript is single-threaded. So, functions take turns for a piece of CPU time, and the time they have to wait varies, depending on the load. This is what causes latency in timers that can be up to 2-3msec. And this latency tends to accumulate. It’s crucially important, when controlling transient processes.
Personally I came across an impossibility to create an accurate timer by standard means: setTimeout() и setInterval() a couple of months ago, when I was working at a small project. The latency came up to inacceptable 0.5 sec.
James Edwards, a freelance web developer, specializing in JavaScript application development, suggests solving the task of accurate timing this way. The first thing to do to keep the timer accurate is to work out exactly how inaccurate it is, and subtract that difference from the next iteration. So, the following code was written:
var start = new Date().getTime(),
time = 0,
elapsed = ‘0.0’;
function instance()
{
time += 100;
elapsed = Math.floor(time / 100) / 10;
if(Math.round(elapsed) == elapsed) { elapsed += ‘.0’; }
var diff = (new Date().getTime() – start) – time;
IR.SetTimeout((100 – diff), instance);
}
IR.SetTimeout(100, instance,);
It’s a simple and good solution. The advantage is that it does not matter how inaccurate the timer is, as consequently the small latency of 3-4ms can be easily compensated. Whereas inaccuracy of a regular timer accumulates with each iteration and becomes noticeable.
As I mentioned I came across a problem of inaccurate times when working at a small audio project. After going into theory of creating accurate times in JS, I wrote the following code on the basis of the one suggested by James Edwards.
//when pressing “play/stop”, a timer function is activated
function preciousTimer (step) {
//like in examples above, we take DateStamp for evaluation
var start = new Date().getTime(),
time = 0,
/*this variable was caused by the necessity
to have an even number as many iterations
as steps in the sequencer (the accuracy is still low)*/
it = 0;
function instance () {
//calculate the ideal time
time += step;
//calculate the difference
var diff = (new Date().getTime()- start) – time;
//act by the iterator value
if (it == 4) {
it = 0;
/*a place of sequencer working with matrix,
here we see the value of logic arrays
for every passage. */
if (m == 8) {
m = 0;
};
for (var i = 0; i < 4; i++) {
if (noteArr[i][m]) {
sound[i].play();
};
};
m++;
};
it++;
//if “pause” is pressed during an iteration,
//leave the end of the recursive chain
if (pause) {
return;
};
//call the next iteration, considering the latency
IR.SetTimeout((step – diff), instance);
};
//It’s the first call of instance function(),
//that starts the consequent call of iterations
setTimeout(step, instance);
};
The code written by me allows to play music continually, without time-lags. And it’s only one of the variants of using the code, written by James Edwards. Using it as a basis you can write your own self-adjusting timer for any purpose you want.
You can read the original of the article, used as a starting point of this post, here: Сreating accurate timers in JavaScript