Bringing setTimeout to ECMAScript

David Bruant david.bruant at labri.fr
Sun Mar 20 07:18:23 PDT 2011


Le 20/03/2011 14:33, Jorge Chamorro a écrit :
> On 20/03/2011, at 13:51, Jorge wrote:
>> On 20/03/2011, at 12:08, David Bruant wrote:
>>> Le 20/03/2011 04:11, Brendan Eich a écrit :
>>>> On Mar 19, 2011, at 4:20 PM, Sam Tobin-Hochstadt wrote:
>>>>
>>>>> On Sat, Mar 19, 2011 at 6:50 PM, Brendan Eich <brendan at mozilla.com> wrote:
>>>>>> setTimeout does not introduce threads, shared memory among them, or even
>>>>>> non-determinism if we spec carefully (browsers have to implement carefully
>>>>>> already).
>>>>> `setTimeout' already introduces nondeterminism based on the speed of
>>>>> the implementation.  Consider:
>>>>>
>>>>> setTimeout(f1,1000)
>>>>> compute()
>>>>> setTimeout(f2,0)
>>>>>
>>>>> If `compute' takes a long time, then `f1' runs before `f2', otherwise
>>>>> `f2' runs first.
>>>> Isn't the non-determinism entirely in compute(), so that if you replace the two setTimeout calls with Date.now calls, saving results, you can measure the ND that either does or does not reorder f1 with respect to f2?
>>>>
>>>> My point was that setTimeout, unlike threads racing over shared mutable state, does not introduce new sources of ND not already in the current execution model.
>>>>
>>>> We need to be careful about order, though. If setTimeout(f1, 1000) schedules f1 to be called at t1, and setTimeout(f2, 0) schedules f2 at t2, then if t2 >= t1, f1 should be called first. I'm not sure all browsers implement this.
>>> I'm sorry, but even though I agree on the principle, I do not know why
>>> "f1 /should/ be called first".
>>> With names:
>>> ----
>>> setTimeout(f1, delay1);
>>> computea();
>>> setTimeout(f2, delay2);
>>> computeb(); // to enforce the idea that the program doesn't stop right away
>>> ----
>>> At the end, f1 is scheduled at t1, f2 at t2. (t1<t and t2<t with t
>>> present time). We have two timeouts ready to be fired, there is a
>>> decision that has to be made on the firing order. I would personnally
>>> choose yours, which is to call the function that has been the most
>>> delayed (max(t - t_i)). However, other decision policies could be valid.
>>> For instance, choosing max( (t-t_i)/delay_i ) could be a valid policy
>>> too. The rationale would be to keep at a minimum not the absolute delay,
>>> but the relative delay.
>>> Another thing that could be taken into account is heuristics on the time
>>> that f1 and f2 take to execute.
>>> Mixing all these things together, there are certainly other valid
>>> policies that could be considered.
>>>
>>> Once again, my personal preference, the policy I find the most fair, is
>>> reducing absolute delay as you suggest, but is there a reason why this
>>> /should/ be the behavior accross browsers? Should even the behavior be
>>> consistent across browser? Across hardware, ES engine implementation and
>>> external factors (OS scheduling with other programs), computea and
>>> computeb can make t1 and t2 relative order different from one run to
>>> another. So there is no way to test the consistency.
>>>
>>> Is there a reason why you're expecting browsers 1) to be consistent in
>>> their policies 2) to choose a particular policy?
>> A timer that expires is an event, and I would expect events to be serviced in the order they happen. As when I click twice, I'd expect the first click to be serviced before the second click.
>>
>> So given 2 timers, expiring at t0 and t1 with t0 < t1, if Date.now() is >= t0 and >= t1, I would expect t0 to be serviced first, yes.
The difference is that the system can understand what is your
expectation as a user when you've clicked twice. Both click are clearly
sequenced. For timers, the non-determinism due to the computation time
of computea and computeb prevents you from /expecting/ anything. Once
again, I agree with the policy, but there is no way to enforce it within
the spec.
There is no way to write an ECMAScript test to be added to test262 to
tell which implementation is valid and which is not. For anything tied
to real time, it's impossible. The best test that could be written for
Date.now() is to make sure that the returned value is bigger than the
date when the test has been written. Or maybe, making sure that two
sequential calls verify that the time goes forward. That's the best we
can do.
I do not really understand how you can "expect" things if you can't
verify if your expectation is met or not.

In low-memory environment, if a program does an intensive use of timers,
maybe that heuristics on the time the timer firing will take could be
used to try to get rid of a maximum of timers as soon as possible to
save up memory. I would consider this policy as valid due to environment
constraints.

> And if t0 were === t1, I would also expect them to be serviced in the same order in which they were setup:
>
> setTimeout( f1, 0 );
> setTimeout( f2, 0 );
> setTimeout( f3, 0 );
> setTimeout( f4, 0 );
> setTimeout( f5, 0 );
>
> ->
> f1()
> f2()
> f3()
> f4()
> f5()
I think it is very dangerous to use talk about things like t0 === t1 and
Date.now() >= t0 (concerned about the "or equal"). If ECMAScript has
millisecond as granularity, most systems have microseconds if not
nanoseconds. 1ms = 10^(6)ns. That's a lot! It leaves a lot of room for
interpretation. And even the setTimeout calls aren't instantaneous.

Consider (milliseconds in comment):
// 0
setTimeout( f1, 1 );
setTimeout( f2, 0 ); // 1 (millisecond change in the middle of the call)
// 2
// -- decision to make on which timer to fire.
Since the millisecond change happened during the second setTimeout, when
is scheduled this second timeout? We can arbitrarly choose one, but I do
not know why we would do so.
Time is not discrete and especially not milliseconds.
The most accurate thing we could discretize and base timing on is clock
ticks. But this is not a "real time" unit and there is no absolute
relationship between clock ticks and real time. How accurate was Intel
when they sold me a "2GHz processor"? It certainly changes throughout
time and with external conditions (temperature...) too.

As pointed out by Dave Herman, real time is difficult to take into
account. Having strong expectations on real time ("I want this timer to
fire before this one under such real-time-dependent conditions") within
a programming language doesn't like a good idea.

David
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20110320/c334e695/attachment-0001.html>


More information about the es-discuss mailing list