Shouldn't timers be specified?

# Brandon Benvie (14 years ago)

I just finished answering this question on StackOverflow and it got me thinking about the obvious: timers are not specified yet are central to a vast swath of JavaScript code. Timers in Node.js have a significantly higher resolution than what is found in browsers: setTimeout(fn, 1) will, in fact, execute in 1 millisecond (assuming the system isn't taxed to the point of being unresponsive). Browsers have collectively implemented a floor at around 15ms. Code that works fine in a browser can very well melt the computer if run in Node. For reference, here's the answer I wrote on StackOverflow;

It doesn't have a minimum delay and this is actually a compatibility issue between browsers and node. Timers are completely unspecified and node implements them simply due to how fundamental they've been in JavaScript's history and how irreplaceable they are otherwise.

Node uses libuv which a cross-platform abstraction layer for lower level system things like file-system, networking stuff, etc. One of those things is timers, which Node provides a minimal wrapper around. At the libuv level, the timers used are the system-specific high precision timers. In Windows, for example, this is implemented using QueryPerformanceFrequency and FileTimeToSystemTime which provides resolution measured in nanoseconds.

msdn.microsoft.com/en-us/library/windows/desktop/ms644905(v=vs.85).aspx

msdn.microsoft.com/en-us/library/windows/desktop/ms724280(v=vs.85).aspx

# Brandon Benvie (14 years ago)

Correction: it is specified in HTML5 here www.whatwg.org/specs/web-apps/current-work/multipage/timers.html#timers .

Suffice to say that a DOM specification isn't sufficient for something so central to JavaScript, nor is it the specification currently followed by browsers anyway.

# Brendan Eich (14 years ago)

Brandon Benvie <mailto:brandon at brandonbenvie.com> January 21, 2012 7:37 PM Correction: it is specified in HTML5 here www.whatwg.org/specs/web-apps/current-work/multipage/timers.html#timers.

Suffice to say that a DOM specification isn't sufficient for something so central to JavaScript, nor is it the specification currently followed by browsers anyway.

Browsers definitely have to agree on things such as this step:

  • If timeout is less than 4, then increase timeout to 4.

And the modern ones, AFAIK, do (old ones use 10). THe spec is not the same for Node.js and we cannot unify toward 1ms resolution given web compatibility constraints found out the hard way (most recently by Chrome folks).

Possibly it's time to try again, but whatever the case: what's required is an experimental regime, not a rushed de-jure standardization mis-step in ECMA-262.

We've considered setTimeout/setInterval/setImmediate, along with event loop concurrency (also in HTML5). They won't make ES6. Maybe next time, but IMHO we need more convergence between browsers and Node, and more inductive learning.

# Brandon Benvie (14 years ago)

Absolutely agree. I don't see a place for Node's 1ms resolution in browsers, which was the impetus for raising the issue. I see a place for Node (and other non-browser platforms) to implement their own host timers that provide higher resolution (In fact Node's process.nextTick(callback) is a good example of host functionality that's useful but wouldn't belong in a JS spec). But the point is that the lack of specification has already resulted in incompatible implementations of ostensibly the same basically required core language functionality.

# Brandon Benvie (14 years ago)

For reference, here's the start of an es-discuss thread on the topic from March 2011: esdiscuss/2011-March/013129

Here's a reference on implementing timer functions in Rhino:

stackoverflow.com/questions/2261705/how-to-run-a-javascript-function-asynchronously-without-using-settimeout

You can use java.util.Timerdownload.oracle.com/javase/1.5.0/docs/api/java/util/Timer.html and java.util.TimerTaskdownload.oracle.com/javase/1.5.0/docs/api/java/util/TimerTask.html

to roll your own set/clear Timeout and set/clear Interval functions:

var setTimeout, clearTimeout, setInterval, clearInterval;

(function () { var timer = new java.util.Timer(); var counter = 1; var ids = {};

setTimeout = function (fn,delay) {
    var id = counter++;
    ids[id] = new JavaAdapter(java.util.TimerTask,{run: fn});
    timer.schedule(ids[id],delay);
    return id;
}

clearTimeout = function (id) {
    ids[id].cancel();
    timer.purge();
    delete ids[id];
}

setInterval = function (fn,delay) {
    var id = counter++;
    ids[id] = new JavaAdapter(java.util.TimerTask,{run: fn});
    timer.schedule(ids[id],delay,delay);
    return id;
}

clearInterval = clearTimeout;

})()

Looking for the Spidermonkey equivalent currently. Regardless, it seems like something that needs to be implemented at the language level, and has wide support for it. There's a lot on the table for ES6 and it's pretty late in the game (well after technical feature freeze) so I definitely see why it wouldn't make the cut. But if not for ES6, this needs to be in ES next text, and as something already implemented in nearly all JS envs, simply informally agreeing on the fundamentals would be enough to get it most of the way there implementation-wise in most implementations.

# Brandon Benvie (14 years ago)

Sorry to spam this thread but I wanted to get the relevent points in up front:

'Actually, wait a minute -- I think I disagree with you here. WHATWG specifies the specific event queue of the browser. Node.js has its own event queue. Others may as well. The unofficial agreement of JS has always been, no matter where you embed it, it should never have pre-emption. So what we would be specifying is the rough concurrency framework required of any JS embedding. In other words, it would be a more abstract specification of event queues, of which WHATWG event queues are a valid implementation.'

Spec the unofficial agreement, including the minimal(/maximal if it exists) time constraints, and go from there. This is needed.

# Andrea Giammarchi (14 years ago)

process.nextTick already landed in browsers, as concept, it's called setImmediate

msdn.microsoft.com/en-us/library/ie/hh673556(v=vs.85).aspx#setimmediate

About Rhino, that implementation is not the equivalent of what we have in browsers, where the most useful thing ever is rarely used out there even if completely cross browsers but IE where de-facto standard is shim amble without problems.

I am talking about extra arguments any setInterval/Timeout accept, i.e.

setTimeout(callback, 1, some, thing);

where callback is

function callback(some, thing) { ... }

and arguments will be sent when the timeout is burned.

Here fully node.js compatible Rhino timers I have used in wru: WebReflection/wru/blob/master/src/rhinoTimers.js

Said that, the fact node.js and browsers are sometimes way too much misaligned is something I have blogged about already and in this case node.js does not even return an Int32 as any browsers does, it returns an object, still unique, but not an Number.

It would be nice to have these methods well defined across all platforms

br

# Brandon Benvie (14 years ago)

Essentially: there's definitely a lot of things that will and do exist in JS that are platform specific implementations and even platform specific in existence. Timers aren't something that are platform specific in existence. A JS implementation that lacks timer functions is considered deficient, and is practically deficient. This despite timers being part of no JS spec.

# David Bruant (14 years ago)

Le 22/01/2012 06:36, Brandon Benvie a écrit :

For reference, here's the start of an es-discuss thread on the topic from March 2011: esdiscuss/2011-March/013129

Indeed. Two notable answers by Mark Miller [1] [2] indicate an intention to bring setTimeout to ECMAScript. The basic idea would to be to make Q.delay [3] a native construct of the language (and specify setTimeout and setInterval as implementations based on Q.delay (with clamping where necessary for compat reasons)). All this work would come along the work on concurrency which would bring the event loop in ECMAScript.

David

[1] esdiscuss/2011-March/013136 [2] esdiscuss/2011-March/013213 [3] strawman:concurrency#q.delay

# Brendan Eich (14 years ago)

Brandon Benvie <mailto:brandon at brandonbenvie.com> January 21, 2012 9:59 PM Sorry to spam this thread but I wanted to get the relevent points in up front:

'Actually, wait a minute -- I think I disagree with you here.

On what? Being past the deadline? Not rushing a de-jure standard before we have synthesized the right semantics from relevant JS embeddings?

Spec the unofficial agreement, including the minimal(/maximal if it exists) time constraints, and go from there. This is needed.

Why? What goes wrong if we go light on execution model one more time? I think nothing.

But in fact we are going to get a little more into execution model in ES6. How much remains to be seen. We discussed it at last week's meeting.

But this is not an all-or-nothing proposition, and I do not see the do-or-die requirement. Reality is what it is. HTML5 captures a lot. Node.js conforms. ES6 saying more doesn't alter these facts.

# Rick Waldron (14 years ago)

This is a perfect use case for the forth-coming module system (similar to the way Globalization is being developed). Dave Herman and I had a brief "over Twitter" exchange that began with my desire for a migration of parseInt and parseFloat to Math, which I followed with a suggestion to do the same with setTimeout and setInterval (despite those currently existing in the realm of DOM APIs) to the imaginary Timer object.

# Jorge (14 years ago)

On 22/01/2012, at 21:00, Brendan Eich wrote:

Brandon Benvie <mailto:brandon at brandonbenvie.com> January 21, 2012 9:59 PM Sorry to spam this thread but I wanted to get the relevent points in up front:

'Actually, wait a minute -- I think I disagree with you here.

On what? Being past the deadline? Not rushing a de-jure standard before we have synthesized the right semantics from relevant JS embeddings?

Spec the unofficial agreement, including the minimal(/maximal if it exists) time constraints, and go from there. This is needed.

Why? What goes wrong if we go light on execution model one more time? I think nothing.

But in fact we are going to get a little more into execution model in ES6. How much remains to be seen. We discussed it at last week's meeting.

But this is not an all-or-nothing proposition, and I do not see the do-or-die requirement. Reality is what it is. HTML5 captures a lot. Node.js conforms. ES6 saying more doesn't alter these facts.

Now isn't that ~ the opposite of what you said on 2011-03-18 in David Bruants' "Bringing setTimeout to ECMAScript" thread ?

<quote>

Add to that the fact that Netscape and Microsoft failed, or chose not to, standardize the DOM level 0, and we have the current split where setTimeout is in HTML5 but the core language is embedded with increasing success in non-browser, no-DOM host environments that want setTimeout.

I'm open to Ecma TC39 absorbing setTimeout and the minimum machinery it entrains. We should ping Hixie. </quote>

Why ? What has changed ?

P.S. Node.js does not conform. Not at all. Not only it doesn't clamp to 4ms (which happens to be a good thing, IMO), but its timers often fire out of order !

# Brendan Eich (14 years ago)

Rick Waldron <mailto:waldron.rick at gmail.com> January 22, 2012 12:50 PM This is a perfect use case for the forth-coming module system (similar to the way Globalization is being developed). Dave Herman and I had a brief "over Twitter" exchange that began with my desire for a migration of parseInt and parseFloat to Math,

or Number -- IIRC, Crock proposed making better-behaved parse methods live there.

which I followed with a suggestion to do the same with setTimeout and setInterval (despite those currently existing in the realm of DOM APIs) to the imaginary Timer object.

Right :-P.

# Brendan Eich (14 years ago)

Jorge <mailto:jorge at jorgechamorro.com> January 22, 2012 1:35 PM

Now isn't that ~ the opposite of what you said on 2011-03-18 in David Bruants' "Bringing setTimeout to ECMAScript" thread ?

Is this a "gotcha" game? Notice the date. Our cutoff for ES6 features was 2011-05. That's one thing that changed. But also, try to read more carefully:

<quote> Add to that the fact that Netscape and Microsoft failed, or chose not to, standardize the DOM level 0, and we have the current split where setTimeout is in HTML5 but the core language is embedded with increasing success in non-browser, no-DOM host environments that want setTimeout.

I'm open to Ecma TC39 absorbing setTimeout and the minimum machinery it entrains. We should ping Hixie.

Nothing, and I mean nothing, that I wrote here contradicts what I wrote in reply to Brandon. Ecma TC39 is almost certainly going to absorb event loop, timeout, and other specs from the WHAT-WG / W3C (or duplicate them).

Why do you insist on taking one thing I wrote and misreading it as contradicting another thing (namely, timing re: ES6, Node's 1ms vs. HTML5's 4ms lack of agreement indicating more synthesis needed, etc.)?

</quote>

Why ? What has changed ?

P.S. Node.js does not conform. Not at all. Not only it doesn't clamp to 4ms (which happens to be a good thing, IMO), but its timers often fire out of order !

Here you clearly misread my reply to Brandon -- I was citing modern browsers' clamping at 4ms, per HTML5, in contradiction to Node's 1ms as cited by Brandon.

But I didn't know Node does not preserve FIFO order. That seems like an easy bug to fix. Is it on file, do you know?

# Rick Waldron (14 years ago)

On Sun, Jan 22, 2012 at 10:29 PM, Brendan Eich <brendan at mozilla.org> wrote:

Rick Waldron <mailto:waldron.rick at gmail.com**>

January 22, 2012 12:50 PM

This is a perfect use case for the forth-coming module system (similar to the way Globalization is being developed). Dave Herman and I had a brief "over Twitter" exchange that began with my desire for a migration of parseInt and parseFloat to Math,

or Number -- IIRC, Crock proposed making better-behaved parse methods live there.

Number could work as well, but there are no other static methods on Number. Math makes sense to me because Math is already in the business of doing smart coercion...

Math.max("1", 0); // 1

// In my fantasy world... Math.parseInt("1", 10); // 1

which I followed with a suggestion to do the same with setTimeout and

setInterval (despite those currently existing in the realm of DOM APIs) to the imaginary Timer object.

Right :-P.

That part was mostly a snarky jab at myself for incorrectly thinking that the existing timer functions were ES global object methods. whoops.

# Rick Waldron (14 years ago)

Node.js does not conform. Not at all. Not only it doesn't clamp to 4ms (which happens to be a good thing, IMO), but its timers often fire out of order !

Is there a reference or test case you can cite for this?

# Mikeal Rogers (14 years ago)

On Jan 22, 2012, at January 22, 20121:35 PM, Jorge wrote:

. Not at all. Not only it doesn't clamp to 4ms (which happens to be a good thing, IMO), but its timers often fire out of order !

node.js does not conform to the 4ms clamp because that would be silly. It does not fire timers out of order, that I know of. If you have a case where that is not true then it's a bug in libuv (setTimeout's event system is in libuv now) that we need to have fixed.

# Andrea Giammarchi (14 years ago)

var d = new Date, i = setInterval(function () {console.log(new Date - d); d = new Date;}, 1);

most likely gonna fire a sequence of

10 0 11 0 12 0 10 0 11 0 10 0

... not really reliable, even if delay is specified to 10 o 20, does not look that consistent

with setTimeout, I have tried delay 3 and it's never less than 10 or 11, but with delay 1 is almost always 0: var d = new Date, delay = 3, i = setTimeout(function t() {console.log(new Date - d); d = new Date; i = setTimeout(t, delay);}, delay);

br

# Jorge (14 years ago)

On 23/01/2012, at 04:57, Mikeal Rogers wrote:

On Jan 22, 2012, at January 22, 20121:35 PM, Jorge wrote:

. Not at all. Not only it doesn't clamp to 4ms (which happens to be a good thing, IMO), but its timers often fire out of order !

node.js does not conform to the 4ms clamp because that would be silly.

Exactly groups.google.com/group/nodejs-dev/msg/788492357732e93e

It does not fire timers out of order, that I know of.

groups.google.com/group/nodejs-dev/browse_thread/thread/922a30cf88a1b784

If you have a case where that is not true then it's a bug in libuv (setTimeout's event system is in libuv now) that we need to have fixed.

The test that's been disabled:

joyent/node/blob/master/test/simple/test-next-tick-ordering.js#L50