Bringing setTimeout to ECMAScript

David Bruant david.bruant at labri.fr
Sat Mar 19 10:57:44 PDT 2011


Le 19/03/2011 17:58, Mark S. Miller a écrit :
>
> On Sat, Mar 19, 2011 at 5:59 AM, David Bruant <david.bruant at labri.fr
> <mailto:david.bruant at labri.fr>> wrote:
>
>
>     I fully agree that the current proposal and all related work
>     (yours included) offer very powerful mecanisms and solutions to
>     common problems (I had already read your article on "Who says
>     JavaScript I/O has to be ugly?" and really enjoyed what I saw).
>     However, the tiny brick/element/component/part that is missing to
>     implement "time event" ("clock event"?) is to take time into
>     account in the proposal. No matter how powerful the current
>     proposal is, it is lacking this elementary piece in order to
>     implement/standardize setTimeout.
>     And I intuit it wouldn't be that hard to add it. I am not very
>     familiar with promises but from what I understand, having the
>     ability to create a "timed promise" which resolution would be
>     handled by the engine could be a solution. Once again, I'm not
>     familiar with promises, so this idea may sound stupid, but people
>     who are familiar with promises and the Q API will certainly have
>     better ideas on integrating the notion of time to the concept in a
>     way that could make setTimeout and friends implementable on top of
>     this integration.
>
>
> The idea is not stupid at all. It's perfectly sound. For example, the
> delay example you noticed could be made primitive and setTimeout built
> out of that. Either can be built from the other. The advantage of
> layering setTimeout on a new primitive, whether delay or
> <http://nodejs.org/docs/v0.4.3/api/all.html#process.nextTick> or
> something else, is that the new primitive can avoid spec weirdnesses
> already entrenched for setTimeout, like this 4ms clamping. Instead,
> this 4ms weirdness could just be specifically part of setTimeout's
> behavior.
>
> Layering the other way, with setTimeout at the bottom, would mean the
> event loop could never run faster than 4ms per turn. This is
> unacceptable, and probably has been since the mid '70s. Should we
> clamp our fast our CPUs can execute instructions as well? That said, I
> think something like setTimeout with better semantics is the right
> lower layer abstraction. The two things I'd fix in this lower layer
> abstraction:
>
> * No clamping. Time runs as fast as the platform lets it run.
> * The return value is not an integer but a unique unforgeable object
> for canceling the event. No one without that object can cancel that event.
This last point is something I was about to raise when starting to think
about extending the Q API.
setTimeout returns a number, so a malicious could loop through numbers
and call clearTimeout on them. An unforgeable object sounds like the
correct response to this issue. Have you considered wrapping
setTimeout&friends in SES with this solution? It wouldn't break code
which do not rely on the returned value being a number (but would break
code which does, of course). I think there would be a need to wrapped
the passed callback in order to achieve garbage collection.

I agree on the rest you've said except one thing: I'm not really sure ES
should standardized the 4ms clamping. It is a reality in web browsers
and maybe fair for the WHATWG to standardize it as such for web backward
compatibility, but maybe that other non-web browser ES-based
implementations do not follow this 4ms restriction. Any idea if there is
a 4ms clamping in node.js setTimeout? Or in other ES-based implementations?
If there is none, the ECMAScript spec could just leave some room to
implementation-dependent behaviors.



After giving it further thought, here are the ideas I've had on adding
time to the Q API:
Q.when(timedPromise, success); would be a nice syntax to call a
'success' function when the promise is resolved.

To reject a timedDefered, something like:
timedDeferred.resolve(Q.reject('')) could do it. But it requires
providing the resolver to the timedDeferred creator. I do not know if
it's a good idea to provide the resolver to user script since, in the
way I see it, the resolver should exclusively be given to the engine
which has the responsibility to manage time. I may be wrong. It however
could be an occasion to trigger a promise resolution in advance.
In Kris Kowal Q implementation (my (untouched) fork
https://github.com/DavidBruant/q/blob/master/lib/q.js#L135), 'reject' is
provided as part of the promise if I understand well. Providing the
rejecter but not the resolver could be a way to solve the second use
case without providing the resolver to the user script.
Do people have opinions on the resolver being provided or not to the
user in case of a timed defered?

Something that could be convenient in the timedPromise/Deferred
construtor would be to be allowed to pass a Date object. If I want a
promise to be resolved when my next birthday happens, I would prefer to
write Q.timedDefer( Date(2012, 3, 8, 12) ) instead of computing
milliseconds since 1/1/70. A decision would have to be made for dates in
the past (actually, for negative number of milliseconds too)

On the constructor itself, maybe an optional argument could be given to
Q.defer. Maybe it would be better to have a Q.timedDefer function. These
are just ideas. I have no strong opinion.

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


More information about the es-discuss mailing list