Bringing setTimeout to ECMAScript

Kyle Simpson getify at gmail.com
Sun Mar 20 12:03:34 PDT 2011


>> Nowadays the clamp is there because sites use |setTimeout(f, 0)| when 
>> they really mean "run this at 10Hz" and if you run it with no delay then 
>> they swamp your event loop and possible render "wrong" (e.g. the text 
>> disappears before the user has a chance to read it).
> I'm not convinced that this  is the meaning. I use |setTimeout(f, 0)| to 
> mean "schedule f after this event completes" or "push |f| onto the event 
> queue"; I think that is the common meaning.   A delay value of zero is 
> perfectly sensible, but we mean "zero seconds after other queued events", 
> not "zero seconds after this event".  We assume (without real evidence I 
> suppose) that UI and IO events can be queued while our JS (the caller of 
> |setTimeout(f, 0)|) runs.

I'd actually say that the most common meaning for `setTimeout(f,0)` is: "do 
`f` as soon as possible after the current code finishes." There's a bunch of 
places I do things like that. For instance, in IE (older versions), it's 
prudent to delay any code with a setTimeout(..., 0); that is adding script 
elements to the DOM, to avoid certain crashing race conditions. And there's 
of course dozens of other cases where similar things are a reality on the 
web.

If:

setTimeout(a,0);
setTimeout(b,0);
// some non-trivial computation

... is really to be interpreted that `a` and `b` have a non-deterministic 
ordering, that's quite counter-intuitive and in fact will definitely have 
potential to break some code across the web. On the contrary, I've never 
seen that pattern be unreliable, so I would suspect all the browsers are 
already guaranteeing that order, using some "queue" (not a "stack", 
obviously, as Jorge has been saying) for each target time.

Furthermore, this pattern should also be true here, right?

setTimeout(a,5);
var then = (new Date()).getTime(), now;
do { now = (new Date()).getTime(); } while (now < (then + 5));
setTimeout(b,0);

If in this case `b` can go before `a`, that seems like that violates the 
principle of least-surprise, because as a programmer I've basically tried to 
ensure with that snippet that both timers are set to fire at essentially the 
same time target, and if they are firing at ~ the same time, I can't see any 
expectation that makes sense except "first-come-first-served" (in other 
words, the time-target queueing).

There are cases where non-determinism are unfortunate reality, like the 
iteration order of objects :), but I don't think that timer/event ordering 
should be one of them, if it can be avoided.


> Multiple repeated calls to |setTimeout(f,0)| are bugs

I don't agree with that assertion at all. Two different functions might 
"queue up" two different snippets to happen "as soon as possible, later", 
each of them using their own setTimeout(..., 0).


> and setInterval of zero would be a bug.

setInterval(...,0) may be silly, but that doesn't mean it's a bug. It means 
"make this happen as fast as possible", just like above where 
setTimeout(...,0)  means "make this happen as soon as possible".

The "swamping" would occur if setInterval(f,0) was actually going to spin in 
sub-millisecond speeds. It could also occur if you fake setInterval with:

function f() {
   // ...
   setTimeout(f,0);
}
f();

But in either of those cases, I don't see why there'd be any reason for 
"clamping" at anything higher than 1ms (being the smallest unit of time I 
can address with the API anyway)?



--Kyle


 



More information about the es-discuss mailing list