PDA

View Full Version : setTimeout vagaries



jscheuer1
09-14-2008, 05:21 AM
Ever notice how in scripts where you do something like (snippet based loosely upon my updated version of Circling text trail script (http://www.dynamicdrive.com/forums/showpost.php?p=161254&postcount=2) originally by Tim Tilton):


function drag(){
y[0] = Math.round(Y[0] += ((ymouse) - Y[0]) * speed);
x[0] = Math.round(X[0] += ((xmouse) - X[0]) * speed);
for (var i = n; i > 0; --i){
y[i] = Math.round(Y[i] += (y[i-1] - Y[i]) * speed);
x[i] = Math.round(X[i] += (x[i-1] - X[i]) * speed);
};
makecircle();
setTimeout(drag, 20);
}

that different browsers run the code at different speeds?

Well, I have and it has always bothered me. I got this inspiration though just recently to test the timeout interval against instances of the Date object and to adjust said timeout interval based upon that (actual code snippets):


var n = msg.length - 1, a = Math.round(size * diameter * 0.208333), inv = 20, unv = inv,


drag = function(){ // makes the resistance
if(abstime.l && abstime.l > 0)
abstime(abstime.a || false);
y[0] = Math.round(Y[0] += ((ymouse) - Y[0]) * speed);
x[0] = Math.round(X[0] += ((xmouse) - X[0]) * speed);
for (var i = n; i > 0; --i){
y[i] = Math.round(Y[i] += (y[i-1] - Y[i]) * speed);
x[i] = Math.round(X[i] += (x[i-1] - X[i]) * speed);
};
makecircle();
setTimeout(drag, unv);
},


abstime = function(be){
abstime.l--;
if(be) abstime.b = new Date();
else abstime.e = new Date();
if (abstime.b && abstime.e && abstime.l && abstime.l > 0){
abstime.ms = Math.abs(abstime.b.valueOf() - abstime.e.valueOf());
unv = abstime.ms > inv? unv - 1 : abstime.ms < inv? unv + 1 : unv;
abstime.ar[abstime.ar.length] = abstime.ms;
}
else if(abstime.ms) unv = Math.round(eval(abstime.ar.join('+')) / abstime.ar.length);
abstime.a = !abstime.a;
};

abstime.l = 100;
abstime.ar = [];

What this does for the first 99 or so iterations of the code is test the actual intended timeout interval (inv, 20 in this case) against the actual time elapsed between each execution, and adjust the used timeout interval (unv) up or down to attempt to achieve the intended interval.

After the 99 or so tries, abstime sets the timeout interval based upon an average of all the tries which were stored in the abstime.ar array, and then stops checking and adjusting things, so it is really a very small addition to the code execution wise.

I was surprised that this actually worked (got various browsers to perform at the virtually same speed, at least as far as the eye could tell), and even more so that the value arrived at was always about the same (+-1, 23/24, in this case) regardless of browser, and a higher value than I would have expected for any of them except the fastest one.

What I concluded from this (borne out by testing) was that on my system 20 was too short of a timeout interval, had I just used 23 or 24 to begin with, it would have been just fine without all this extra code. But what about other computers?

And, with this added code (or simply using 24) the script ran much more smoothly in the browser (FF) where it had been fast and a bit jerky at 20.

This leads me to believe that the famed jerkiness (for many javascript animation type actions) in FF is a result of it actually trying to adhere to set intervals rather than adapting them to what it can actually do smoothly. IE and others (Safari, Opera) appeared to adapt automatically, but with varying end result intervals.

With the added code however, all mentioned browsers appeared to settle on about the same apparent speed, and I would think that this would work on any computer capable of executing the actual arrived at interval.

Comments?

Master_script_maker
09-14-2008, 05:35 PM
wow, i never would of though of that. but instead of including this in scripts, i could see the as a debugger or perfecter to fix the timing in scripts.

jscheuer1
09-14-2008, 08:11 PM
I was thinking that too. However, since I cannot test on every computer, it might be best just to use the code as part of your script. That way each computer could (at least theoretically) arrive at the correct number for the timeout interval for any particular browser it is running. As I said, the execution load is very small and transient (ends after a short time).

jscheuer1
09-16-2008, 02:41 AM
Update -

I've been playing around with this idea, and as I suspected (but did not mention) might be the case, it appears that the positive results I got initially were more of a coincidence than anything else. For one thing, to be valid under the circumstances described, I would have to average the unv results, rather than the abstime.ms ones as my code was doing. This new approach is better, but still not ideal. Browsers will still present at various speeds, but it does get them closer into alignment speed wise with each other. However, 1000 (rather than 100) iterations or so seems to be required. This is still a relatively low load execution wise though.

Master_script_maker
09-18-2008, 07:51 PM
i think you should submit this to Submit a DHTML or CSS code.

boogyman
09-19-2008, 12:51 PM
or just update the script?

jscheuer1
09-19-2008, 04:10 PM
After playing around with both the abstime and the Circle Text Trail code for quite a bit now, I've decided that abstime isn't really all that workable. It introduces changes in the timeout interval that can make slower browsers appear about as fast as as faster ones, but this can introduce jerkiness.

The differences in speed aren't really all that great anyway without abstime, annoying only to folks who view the script in several different browsers expecting it to be the same speed in all of them.

I'm considering submitting my latest updated version of Circle Text Trail anyway though (without abstime), because it has several improvements over the original. It's more configurable, now uses DOM level 2 to make the trail, exposes no global variables, follows the cursor even on wide pages, and works in modern browsers with or without a valid URL DOCTYPE.

magicyte
10-22-2008, 10:42 PM
Ever notice how in scripts where you do something like (snippet based loosely upon my updated version of Circling text trail script (http://www.dynamicdrive.com/forums/showpost.php?p=161254&postcount=2) originally by Tim Tilton):


function drag(){
y[0] = Math.round(Y[0] += ((ymouse) - Y[0]) * speed);
x[0] = Math.round(X[0] += ((xmouse) - X[0]) * speed);
for (var i = n; i > 0; --i){
y[i] = Math.round(Y[i] += (y[i-1] - Y[i]) * speed);
x[i] = Math.round(X[i] += (x[i-1] - X[i]) * speed);
};
makecircle();
setTimeout(drag, 20);
}

that different browsers run the code at different speeds?

Well, I have and it has always bothered me. I got this inspiration though just recently to test the timeout interval against instances of the Date object and to adjust said timeout interval based upon that (actual code snippets):


var n = msg.length - 1, a = Math.round(size * diameter * 0.208333), inv = 20, unv = inv,


drag = function(){ // makes the resistance
if(abstime.l && abstime.l > 0)
abstime(abstime.a || false);
y[0] = Math.round(Y[0] += ((ymouse) - Y[0]) * speed);
x[0] = Math.round(X[0] += ((xmouse) - X[0]) * speed);
for (var i = n; i > 0; --i){
y[i] = Math.round(Y[i] += (y[i-1] - Y[i]) * speed);
x[i] = Math.round(X[i] += (x[i-1] - X[i]) * speed);
};
makecircle();
setTimeout(drag, unv);
},


abstime = function(be){
abstime.l--;
if(be) abstime.b = new Date();
else abstime.e = new Date();
if (abstime.b && abstime.e && abstime.l && abstime.l > 0){
abstime.ms = Math.abs(abstime.b.valueOf() - abstime.e.valueOf());
unv = abstime.ms > inv? unv - 1 : abstime.ms < inv? unv + 1 : unv;
abstime.ar[abstime.ar.length] = abstime.ms;
}
else if(abstime.ms) unv = Math.round(eval(abstime.ar.join('+')) / abstime.ar.length);
abstime.a = !abstime.a;
};

abstime.l = 100;
abstime.ar = [];

What this does for the first 99 or so iterations of the code is test the actual intended timeout interval (inv, 20 in this case) against the actual time elapsed between each execution, and adjust the used timeout interval (unv) up or down to attempt to achieve the intended interval.

After the 99 or so tries, abstime sets the timeout interval based upon an average of all the tries which were stored in the abstime.ar array, and then stops checking and adjusting things, so it is really a very small addition to the code execution wise.

I was surprised that this actually worked (got various browsers to perform at the virtually same speed, at least as far as the eye could tell), and even more so that the value arrived at was always about the same (+-1, 23/24, in this case) regardless of browser, and a higher value than I would have expected for any of them except the fastest one.

What I concluded from this (borne out by testing) was that on my system 20 was too short of a timeout interval, had I just used 23 or 24 to begin with, it would have been just fine without all this extra code. But what about other computers?

And, with this added code (or simply using 24) the script ran much more smoothly in the browser (FF) where it had been fast and a bit jerky at 20.

This leads me to believe that the famed jerkiness (for many javascript animation type actions) in FF is a result of it actually trying to adhere to set intervals rather than adapting them to what it can actually do smoothly. IE and others (Safari, Opera) appeared to adapt automatically, but with varying end result intervals.

With the added code however, all mentioned browsers appeared to settle on about the same apparent speed, and I would think that this would work on any computer capable of executing the actual arrived at interval.

Comments?

Awesome. I made my own 'set timout' function that uses the time for setting the timeout as well. I used this:


var clock = Date.now || function() {
return new Date().getTime();
};

var set = function(ev,t) {
var start = clock();
var end = (start+t);
var loop;

do {
loop = clock();
}while(loop < end);

// I tried eval(), but Twey suggested I not
setTimeout(ev,0);
};

With this said, I have one more comment. It pauses everything else to do this, so it isn't efficient. I like yours better :).

-magicyte