Bringing setTimeout to ECMAScript

Mark S. Miller erights at
Sat Mar 19 13:35:42 PDT 2011

On Sat, Mar 19, 2011 at 1:05 PM, Mark S. Miller <erights at> wrote:

> On Sat, Mar 19, 2011 at 10:57 AM, David Bruant <david.bruant at>wrote:
>>  Le 19/03/2011 17:58, Mark S. Miller a écrit :
>> [...] 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).
> Caja does exactly this. So far we haven't found any code that this actually
> breaks. All uses we've encountered[1] treat the return value of
> setTimeout/setInterval as simply something they can remember and later pass
> to clearTimeout/clearInterval.
> [1] That I'm aware of. Caja users should speak up if they've hit a
> counter-example. Or anyone else that has seen code in the wild that actually
> counts on these values being numbers.
> I actually haven't thought about this in the context of SES, and I must.
> Thanks for raising this.

Yes, of course SES must do so, as Caja does. I'm not even sure why I needed
a moment to think about this ;).

The raises the issue of how ES-future should specify setTimeout/setInterval,
such that SES remains a compatible fail-stop subset of ES. Should ES leave
unspecified what the return value is, so long as it is acceptable as input
to clearTimeout/clearInterval? That way, SES would be a compatible subset of
ES as spec'ed, even though it would not be a subset of ES as implemented. Or
could we actually get away with changing the setTimeout spec to specify an
unforgeable opaque object? If possible, cleaning this up would be awesome.

>>  I think there would be a need to wrapped the passed callback in order to
>> achieve garbage collection.
> I didn't understand that. Could you expand? Thanks.
>> 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.
> I like this approach. Does anyone know of any problems leaving the 4ms
> issue as dependent on the hosting environment, and not to be standardized as
> part of an ES setTimeout/setInterval standard?
>> 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.
> I don't understand. Given that timedPromise is the kind of thing that
> delay() returns, just doing a Q.when() on a timePromise as above will
> already do the right thing. That's why the delay() and race() abstractions
> compose so nicely -- because race() does a Q.when on the promise returned by
> delay().
> I suspect I'm misunderstanding you. I'll wait for clarification on this
> point before proceeding with the rest.
>> 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
>>, '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
> --
>     Cheers,
>     --MarkM

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <>

More information about the es-discuss mailing list