Bringing setTimeout to ECMAScript

Jorge jorge at jorgechamorro.com
Sun Mar 20 10:53:20 PDT 2011


On 20/03/2011, at 18:11, David Bruant wrote:
> Le 20/03/2011 17:25, Jorge a écrit :
>> 
>> In order to know *exactly* the target time (Date.now() +ms) that a given setTimeout() has been scheduled for, setTimeout() would have to return it (it doesn't currently):
>> 
>> function newSetTimeout ( f, ms ) {
>>  var targetTime= Date.now()+ ms;
>>  scheduleTimeout(f, targetTime);
>>  return [ targetTime ];
>> }
>> 
>> The way it's now, most of the times you can, but *sometimes* you can't tell:
>> 
>> var ms= 50;
>> var t= Date.now();
>> setTimeout(f, ms);
>> if (t === Date.now()) {
>>  //We know: targetTime === t+ms
> I am sorry, but we don't "know". Maybe that by the time we've "reached
> the bracket", the millisecond has changed. We can have been pre-empted
> by the OS scheduler, the system may be slow. There might have been
> garbage collection, maybe a repaint of the screen. There is no guarantee
> when it's about real time. The only guarantee is that the time moves
> forward.

No, no, if Date.now() was === before and after the setTimeout(), it must have been *scheduled* to trigger at t+ms, for sure.

>> }
>> else {
>>  //Not sure, it can be t+ms or t+ms+1
>> }
>> 
>> But honestly, I don't see what your point is.
> When I write setTimeout(f, 1000), I expect f to be called "after at
> least one second" (with the implicit "as soon as possible after the
> given time"). That's what programmers have expected since the beginning
> and implementors cannot really provide a better guarantee.

Of course. We all know that ;-)

> ---
> setTimeout(f1, 1);
> setTimeout(f2, 0);
> compute();
> ---
> As a programmer, since you have no idea of how much time compute is
> going to take, you cannot have any expectation on f1 being called before
> f2

It has nothing to do with compute(), it has to with the target times of the setTimeout()s, which were decided before compute().

> since at the end of compute one millisecond may have passed or not.
> And you organize your program to be independent of the calling order. My
> point is that since you can't rely on a scheduling policy and you
> already organize your program to be independent of the scheduling
> policy, there is no point standardizing the scheduling policy. No one
> will benefit from it. Neither the implementor, nor the programmer.

I have relied on this behaviour many times. For example, when you wanted to do an animation in a browser (before we had CSS animations), you had to rely on this all the time.

> If you write:
> ---
> setTimeout(f1, 0);
> setTimeout(f2, 0);
> ---
> and expect f1 to be called before f2, then why don't you just do
> "setTimeout(function(){f1(); f2();}, 0);" ?

Why would I need to ?

> the language already allows you to do what you want. There is no need to
> enforce the scheduling policy.

There's "no need", but given:

setTimeout(f, 10);
setTimeout(g, 20);

var t = Date.now() + 50;
while ( Date.now() < t ) ;

it's not crazy to expect f() to be called before g()

> If two timers happen to have been scheduled at the same target time by a
> more complicated manner, then it's you are already aware in both calls
> that the system doesn't guarantee anything about real time, so you're
> prepared for a race condition and as such do not have expectations on
> who will be fired first.
> 
> To answer your concern, my point is that imposing the scheduling policy
> won't solve a use case for users and won't help the work of the
> implementors (see my low-memory environment example).
> 
> The more I think about it and give counter-examples, the more I doubt
> what Brendan Eich said that no-determinism can be avoided if the spec is
> carefully written. The non-determinism due to code execution time seems
> to be unavoidable and leaks to any determinism we could try to reach
> with a scheduling policy as long as setTimeout respects "fire after at
> least x milliseconds".

You know the order in which they've been setup (because they've been pushed on stacks), and you know the exact target times of each and every one of these stacks, while it's true that you can't tell for sure the exact time when they're finally going to be serviced, once it arrives, whatever it is ( >= targetTime ), you can (and should, imo) at least dispatch them respecting both the insertion order (pulling from the stacks) and the target times too (servicing the stacks in ascending targetTime order).

I think that would be the right way to do it. And I'd bet that's ~ what Brendan was thinking about when he said "We need to be careful about order, though". But only Brendan knows.
-- 
Jorge.


More information about the es-discuss mailing list