nextTick(f) vs SetTimeout(f, 0)

1,810 views
Skip to first unread message

Jorge

unread,
Aug 27, 2010, 6:55:09 AM8/27/10
to nodejs
This: http://github.com/xk/nodeSnippets/blob/master/nextTick_vs_setTimeout.js

Gives in my Mac :
nextTick: 349589 [174.79 KHz], setTimeout: 349589 [174.79 KHz],
count(nextTick)- count(setTimeout)= 0
nextTick: 526057 [175.35 KHz], setTimeout: 526057 [175.35 KHz],
count(nextTick)- count(setTimeout)= 0
nextTick: 700285 [175.07 KHz], setTimeout: 700284 [175.07 KHz],
count(nextTick)- count(setTimeout)= 1
nextTick: 873390 [174.68 KHz], setTimeout: 873389 [174.68 KHz],
count(nextTick)- count(setTimeout)= 1
nextTick: 1052045 [175.34 KHz], setTimeout: 1052045 [175.34 KHz],
count(nextTick)- count(setTimeout)= 0
..
..

$ node -v
--> v0.2.0

It may be that nextTick() has slowed down (bad), or that setTimeout(,
0) now runs faster, in any case, nextTick() is (no longer) any faster
than a setTimeout(,0). I'm not sure if it's is a bad thing, though,
because I'd prefer setTimeout(,0) to be the nextTick(), instead of
adding a new verb unnecessarily... :-)

http://nodejs.org/api.html : process: process.nextTick(callback) :
says:
"process.nextTick(callback)
On the next loop around the event loop call this callback. This is not
a simple alias to setTimeout(fn, 0), it's much more efficient."

$ cat nextTick_vs_setTimeout.js
/*
2010-08-27 jo...@jorgechamorro.com
Node.js
This program compares the rate of nextTick() vs that of setTimeout(,0)
*/

var nxttick= 0;
var timeout= 0;
var seconds= 0;

function display () {
seconds++;
var txt= "nextTick: "+ nxttick+ " ["+ toKHz(nxttick)+ " KHz]";
txt+= ", setTimeout: "+ timeout+ " ["+ toKHz(timeout)+ " KHz]";
txt+= ", count(nextTick)- count(setTimeout)= "+ (nxttick-timeout);
console.log(txt);
setTimeout(display, 1e3);

function toKHz (count) { return (count/seconds/1e3).toFixed(2); }
};

setTimeout(display, 1e3);

(function ticker () {
nxttick++
process.nextTick(ticker);
})();


(function timer () {
timeout++;
setTimeout(timer, 0);
})();
--
Jorge.

Arnout Kazemier

unread,
Aug 27, 2010, 7:57:01 AM8/27/10
to nod...@googlegroups.com
It's not really about what is faster or not, but which method is more efficient in usage.
nextTick allows you to execute the nextTime the event loop comes again.
This is not the case with setTimeout.

> --
> You received this message because you are subscribed to the Google Groups "nodejs" group.
> To post to this group, send email to nod...@googlegroups.com.
> To unsubscribe from this group, send email to nodejs+un...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/nodejs?hl=en.
>

Bert Belder

unread,
Aug 27, 2010, 8:39:01 AM8/27/10
to nodejs
I think your testing methodology is wrong.

What your program is going to do is:
ticker()
timer()
ticker()
timer()
... etc

So obviously you'll find the same MHz for each.

Run it once with timer() disabled, then run it with ticker() disabled.
You'll see that nextTick() is about 1.5 times faster.

- Bert

Jorge

unread,
Aug 27, 2010, 11:07:02 AM8/27/10
to nodejs
On Aug 27, 2:39 pm, Bert Belder <bertbel...@gmail.com> wrote:
> I think your testing methodology is wrong.
>
> What your program is going to do is:
> ticker()
> timer()
> ticker()
> timer()
> ... etc
>
> So obviously you'll find the same MHz for each.

I think that this:

(function ticker () {
nxttick++
process.nextTick(ticker);
})();

ought to run -by the definition of .nextTick()- at *exactly* the event
loop's speed, and, if this :

(function timer () {
timeout++;
setTimeout(timer, 0);
})();

loops too -in parallel- at exactly the same rate... then they are both
being run at the "next tick".

>
> Run it once with timer() disabled, then run it with ticker() disabled.
> You'll see that nextTick() is about 1.5 times faster.

Yep. When the nextTick() loop is run alone it's twice as fast as the
setTimeout(,0) loop (in my Mac 468 vs 231 KHz). Why is it -the
setTimeout(,0)- comparatively so slow ? Let's patch it :-))

function setTimeout (f, ms) {
if (ms <= 0) return process.nextTick(f);
..
}
--
Jorge.

Marco Rogers

unread,
Aug 27, 2010, 1:50:58 PM8/27/10
to nodejs
We shouldn't be patching setTimeout. It should work the way v8
intends. nextTick is a node construct that is aware of event loop.
It's more efficient and better to use if you don't need a time delay.
It is a replacement for setTimeout. Why worry about how they compare?

:Marco

Timothy Caswell

unread,
Aug 27, 2010, 2:13:47 PM8/27/10
to nod...@googlegroups.com
From what I can tell, they do very different things, both in implementation and semantics.

If I call process.nextTick() 10 times in a single sync tick, they will all 10 be put onto a queue and at the next available "tick" in the event loop, all 10 callbacks will be called in order with a sync for loop. I recently patched this piece of code to be more performant, so you can now queue up thousands of these with very little overhead. It will be one single entry in the event loop and a single for loop over the callbacks, calling them in order.

setTimeout doesn't have such semantics, it depends on system timers and is much less efficient for things that simple need to be deferred till the next tick.

Jorge

unread,
Aug 27, 2010, 2:19:50 PM8/27/10
to nodejs
On Aug 27, 8:13 pm, Timothy Caswell <t...@creationix.com> wrote:
> From what I can tell, they do very different things, both in implementation and semantics.  
>
> If I call process.nextTick() 10 times in a single sync tick, they will all 10 be put onto a queue and at the next available "tick" in the event loop, all 10 callbacks will be called in order with a sync for loop.   I recently patched this piece of code to be more performant, so you can now queue up thousands of these with very little overhead.  It will be one single entry in the event loop and a single for loop over the callbacks, calling them in order.
>
> setTimeout doesn't have such semantics, it depends on system timers and is much less efficient for things that simple need to be deferred till the next tick.

Yep, but in my mind setTimeout(,0) is semantically identical
to .nextTick(). Not so setTimeout(,ms) when ms >= 1.
--
Jorge.

Timothy Caswell

unread,
Aug 27, 2010, 2:24:58 PM8/27/10
to nod...@googlegroups.com
No, because setTimeout means to run the code after AT LEAST the given number of ms. This means it needs to check the clock at least once to see that at least 0 ms have elapsed. Sure we could optimize this special case and merge the two. I in fact asked for this about a year ago on this list. I've since realized that it's good to keep it simple and not confuse the meanings. I would like setTimeout to stay pure and not have any hacked optimizations.

setTimeout(fn) and process.nextTick(fn) do in fact act different in node, and I have often relied on this difference in the past for various needs.

Jorge

unread,
Aug 27, 2010, 2:28:37 PM8/27/10
to nodejs
On Aug 27, 8:24 pm, Timothy Caswell <t...@creationix.com> wrote:
> No, because setTimeout means to run the code after AT LEAST the given number of ms.  This means it needs to check the clock at least once to see that at least 0 ms have elapsed.  Sure we could optimize this special case and merge the two.  I in fact asked for this about a year ago on this list.  I've since realized that it's good to keep it simple and not confuse the meanings.  I would like setTimeout to stay pure and not have any hacked optimizations.
>
> setTimeout(fn) and process.nextTick(fn) do in fact act different in node, and I have often relied on this difference in the past for various needs.

BTW, see what I was doing just right now with your code :

process._tickCallback = function (l) {
if (l= nextTickQueue.length) {
nextTickQueue.forEach(function (f) { f() });
nextTickQueue.splice(0, l);
}
/*
l= nextTickQueue.length;
if (l === 0) return;
for (var i = 0; i < l; i++) {
nextTickQueue[i]();
}
*/
};

:-)
--
Jorge.

Bert Belder

unread,
Aug 27, 2010, 2:29:36 PM8/27/10
to nodejs


On Aug 27, 7:50 pm, Marco Rogers <marco.rog...@gmail.com> wrote:
> We shouldn't be patching setTimeout. It should work the way v8
> intends.  nextTick is a node construct that is aware of event loop.

I don't think setTimeout is implemented by V8, it is originally a DOM
method and nodejs adopted the same syntax.
There are no fundamental reasons not to touch it, especially the (f,0)
case.

That said, I don't care that much.

- Bert

Timothy Caswell

unread,
Aug 27, 2010, 2:38:46 PM8/27/10
to nod...@googlegroups.com

On Aug 27, 2010, at 11:28 AM, Jorge wrote:

> BTW, see what I was doing just right now with your code :
>
> process._tickCallback = function (l) {
> if (l= nextTickQueue.length) {
> nextTickQueue.forEach(function (f) { f() });
> nextTickQueue.splice(0, l);
> }

Keep in mind that forEach is much slower than a plain for(;;) loop. This is a core part of node.js and speed really matters here.

Jorge

unread,
Aug 27, 2010, 2:47:27 PM8/27/10
to nod...@googlegroups.com
On 27/08/2010, at 20:24, Timothy Caswell wrote:

> No, because setTimeout means to run the code after AT LEAST the given number of ms. This means it needs to check the clock at least once to see that at least 0 ms have elapsed.

You must be joking :-)

> Sure we could optimize this special case and merge the two. I in fact asked for this about a year ago on this list. I've since realized that it's good to keep it simple and not confuse the meanings. I would like setTimeout to stay pure and not have any hacked optimizations.

But as we've been using setTimeout(,0) for years in the browsers with the exact same meaning that .nextTick() has, why the need for a new verb ?

> setTimeout(fn) and process.nextTick(fn) do in fact act different in node, and I have often relied on this difference in the past for various needs.

This 4 things are afaics what -currently- make a nextTick(f) !== setTimeout(f,0)

-nextTick() doesn't return any reference.
-You can't remove a function once nextTick'ed().
-You can't pass arguments to a nextTicked() function (not that this is a good thing nor very popular).
-setTimeout creates a needless 0ms new process.Timer() to do what nextTick does much better.

My point is that in the head of any web programmer setTimeout(,0) means do this not now but asap, which is exactly === what .nextTick() does.
--
Jorge.

Jorge

unread,
Aug 27, 2010, 2:49:45 PM8/27/10
to nod...@googlegroups.com

Neither do I, really. But we're very much used to the setTimeout(,0). Why not to "enhance" it as much as we can ? Semantically it's a nexttick...
--
Jorge.

Jorge

unread,
Aug 27, 2010, 2:51:27 PM8/27/10
to nod...@googlegroups.com

Of course.
--
Jorge.

Timothy Caswell

unread,
Aug 27, 2010, 2:52:57 PM8/27/10
to nod...@googlegroups.com
So you are proposing that we take process.nextTick away and force everyone to use the much slower and heavier setTimeout just because that's the only option in the browser?

Even if you put in complex code to optimize setTimeout for the 0ms case, you will still need to implement all the other features of setTimeout for that special case and it will still be much slower.

It's really quite simple, process.nextTick is not a timer. It's a fast, simple, and efficient way to delay some code till the next tick of the event loop. This is a very common need when building async apis like in node.

It will confuse to merge the two meanings into a single function that acts completely different if the value passed in happens to be a 0.

Marco Rogers

unread,
Aug 27, 2010, 3:42:29 PM8/27/10
to nodejs

> I don't think setTimeout is implemented by V8, it is originally a DOM
> method and nodejs adopted the same syntax.
> There are no fundamental reasons not to touch it, especially the (f,0)
> case.
>

Maybe what I said wasn't clear. setTimeout is a javascript
construct. So it's part of the v8 engine, not node. And v8 has done
alot to make sure it runs fast. See http://www.belshe.com/2010/06/04/chrome-cranking-up-the-clock/

But it still won't be as fast a simple process.nextTick for various
reasons states above. In fact I got curious about this and ran the
following test.

var t = function (n){
// print the name so we know which one was called;
return function() {
console.warn(n);
}
}

var i = 10;
while(i--) {
setTimeout(t('setTimeout'), 0);
process.nextTick(t('nextTick'));
}

Guess what gets printed? That's right "nextTick" 10 times and then
"setTimeout" 10 times. That's because the nextTick calls goes
directly on the callstack with no preamble. The setTimeout calls go
into a queue so the delay can be checked against the clock time. Even
though it's 0. So the setTimeout calls come afterwards. Perhaps a
node specific #wtfjs. But it makes sense and it's an indication of
why we should be encouraging people to use process.nextTick.

:Marco

Marco Rogers

unread,
Aug 27, 2010, 3:46:58 PM8/27/10
to nodejs

> "setTimeout" 10 times.  That's because the nextTick calls goes
> directly on the callstack with no preamble.  The setTimeout calls go

whoops

s/callstack/event loop queue/

Camilo Aguilar

unread,
Aug 27, 2010, 3:47:46 PM8/27/10
to nod...@googlegroups.com
Marco, as far I know, setTimeout is implemented in Chrome no v8. Nodejs has its own implementation in src/node.js

Isaac Schlueter

unread,
Aug 27, 2010, 3:51:19 PM8/27/10
to nod...@googlegroups.com
On Fri, Aug 27, 2010 at 12:47, Camilo Aguilar <cam...@cloudescape.com> wrote:
> Marco, as far I know, setTimeout is implemented in Chrome no v8. Nodejs has
> its own implementation in src/node.js

Yep. http://github.com/isaacs/node/blob/master/src/node.js#L589-607

It's a DOM construct, not a JS language construct.

--i

Camilo Aguilar

unread,
Aug 27, 2010, 3:45:01 PM8/27/10
to nod...@googlegroups.com
Jorge, you need free your mind of paradigms when you are learning something new. Do you know what we want to say with event loop in nodejs?. Nodejs isn't a browser. The head of any web programmer has to understand that process.nextTick in Nodejs is the best way in performance terms.

 

leave setTimeout in the browser and use nextTick in nodejs. They are complete different in implementation in nodejs.

Bradley Meck

unread,
Aug 27, 2010, 3:50:30 PM8/27/10
to nodejs
I would just like to point out setTimeout(f,0) being optimized is akin
to setInterval(f,0) being optimizes (note, if setInterval was the
nextTick queue would never end).

Also there is a clear distinction between the 2 logic wise. setTimeout
lets events occur before it occurs. nextTick preempts that.

Marco Rogers

unread,
Aug 27, 2010, 3:56:59 PM8/27/10
to nodejs
Oh. That I was unaware of. Thanks. Makes it even more clear why my
test works the way it does. Looking at this though it does seem
simple to add arguments support to nextTick. Right now you just end
up doing it with closures. But arguments allows you to have a
snapshot rather than working with closure free variables that have
possibly been changed. At least with those passed by value (scalars,
strings).

:Marco

Brian Mitchell

unread,
Aug 27, 2010, 4:02:40 PM8/27/10
to nod...@googlegroups.com
On Fri, Aug 27, 2010 at 15:56, Marco Rogers <marco....@gmail.com> wrote:
> Oh.  That I was unaware of.  Thanks.  Makes it even more clear why my
> test works the way it does.  Looking at this though it does seem
> simple to add arguments support to nextTick.  Right now you just end
> up doing it with closures.  But arguments allows you to have a
> snapshot rather than working with closure free variables that have
> possibly been changed.  At least with those passed by value (scalars,
> strings).

function hello(x) {console.log('hello', x)}
process.nextTick(hello.bind(this, "world"));

Marco Rogers

unread,
Aug 27, 2010, 4:10:41 PM8/27/10
to nod...@googlegroups.com
Yes I know how bind works. It's just for convenience. It's always funny to see which things people demand syntactic sugar for and which are considered "not a big deal".  Wouldn't you rather do this?

     process.nextTick(console.log, "hello ", x);

Ignore the snark Brian. It's not directed at you. I know you're just being helpful.  I'm guilty of this type of thing too.

:Marco

--
You received this message because you are subscribed to the Google Groups "nodejs" group.
To post to this group, send email to nod...@googlegroups.com.
To unsubscribe from this group, send email to nodejs+un...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/nodejs?hl=en.




--
Marco Rogers
marco....@gmail.com

Life is ten percent what happens to you and ninety percent how you respond to it.
- Lou Holtz

Timothy Caswell

unread,
Aug 27, 2010, 4:19:10 PM8/27/10
to nod...@googlegroups.com
Just make some wrapper functions, it's really easy:

function applyNext(fn, args, thisp) {
  process.nextTick(
function () {
    fn.
apply(thisp, args);
  });
}
function callNext(fn) {
  applyNext(fn,
Array.prototype.slice.call(arguments, 1));
}

applyNext(
console.log, ["Hello World"]);
callNext(
console.log, "Hello World");

Marco Rogers

unread,
Aug 27, 2010, 4:36:34 PM8/27/10
to nod...@googlegroups.com
Yeah but this type of thing bothers me when it's done too much.  These type of one off functions are convenient sometimes, but they also litter the code and you waste time tracing them only to find that they are trivial.  But now whenever you see them you have to keep them straight and remember what they do.  I'm thinking of more non-trivial usage than just "print this out on the next tick".

Usually when functions are part of a module api you can glean as much as you need to know with the combination of module name and function name.  But even if you namespaced, these it wouldn't be much clearer without making them longer.

    logging.applyNext?  or even worse the dreaded utils.applyNext?  How about logging.logOnNextTick?  gross.

In comparison, my example isn't much longer than yours.  But from the outset, it's much clearer than both yours and Brian's.  Plus there are no extra functions laying around.

    applyNext(console.log, ["Hello World"]);
    process.nextTick(hello.bind(this, "world"));
    process.nextTick(console.log, "hello ", x);

Obviously this opinion is subjective.  This is just a mini-rant of  mine which is why I threw it in another random thread.  It's just a style preference.  Unfortunately my preference requires me to try to get a core patch committed :(

:Marco

Brian Mitchell

unread,
Aug 27, 2010, 4:55:59 PM8/27/10
to nod...@googlegroups.com

Oh not a problem at all. Just a thought. I personally don't like having to pass 'this' around with bind but it works well.

I also think nextTick is much clearer. Just because the W3C DOM came first doesn't mean we stop trying new things. In time, I think node will find a good balance of new and old JavaScript practice. No sense in prematurely declaring the one true way.

Brian.

>> nodejs+un...@googlegroups.com<nodejs%2Bunsu...@googlegroups.com>

Jorge

unread,
Aug 27, 2010, 4:59:07 PM8/27/10
to nod...@googlegroups.com
On 27/08/2010, at 20:52, Timothy Caswell wrote:
> On Aug 27, 2010, at 11:47 AM, Jorge wrote:
>> On 27/08/2010, at 20:24, Timothy Caswell wrote:
>>
>>> No, because setTimeout means to run the code after AT LEAST the given number of ms. This means it needs to check the clock at least once to see that at least 0 ms have elapsed.
>>
>> You must be joking :-)
>>
>>> Sure we could optimize this special case and merge the two. I in fact asked for this about a year ago on this list. I've since realized that it's good to keep it simple and not confuse the meanings. I would like setTimeout to stay pure and not have any hacked optimizations.
>>
>> But as we've been using setTimeout(,0) for years in the browsers with the exact same meaning that .nextTick() has, why the need for a new verb ?
>>
>>> setTimeout(fn) and process.nextTick(fn) do in fact act different in node, and I have often relied on this difference in the past for various needs.
>>
>> This 4 things are afaics what -currently- make a nextTick(f) !== setTimeout(f,0)
>>
>> -nextTick() doesn't return any reference.
>> -You can't remove a function once nextTick'ed().
>> -You can't pass arguments to a nextTicked() function (not that this is a good thing nor very popular).
>> -setTimeout creates a needless 0ms new process.Timer() to do what nextTick does much better.
>>
>> My point is that in the head of any web programmer setTimeout(,0) means do this not now but asap, which is exactly === what .nextTick() does.
>
> So you are proposing that we take process.nextTick away

No, nextTick is ok where it is.

> and force everyone to use the much slower and heavier setTimeout just because that's the only option in the browser?

No. I'm saying that we could improve setTimeout(,0) and make it as fast as it could be. As fast as nextTick.

> Even if you put in complex code to optimize setTimeout for the 0ms case, you will still need to implement all the other features of setTimeout for that special case and it will still be much slower.

Not if we disguise a call to nextTick in that special case (,0).

> It's really quite simple, process.nextTick is not a timer. It's a fast, simple, and efficient way to delay some code till the next tick of the event loop. This is a very common need when building async apis like in node.

Yep. A timer of 0ms isn't really a timer.

> It will confuse to merge the two meanings into a single function that acts completely different if the value passed in happens to be a 0.

It doesn't make much sense to time 0 ms, does it ? IMO setTimeout(,0) should be doing now ~ exactly what nextTick does.

In any case, as talk is cheap, I'll see what code -if any- can I come up with, so that we have something more concrete to discuss.
--
Jorge.

Bradley Meck

unread,
Aug 27, 2010, 5:23:03 PM8/27/10
to nodejs
setTimeout(f,0) is more than just an optimization if it changes to
nextTick, it changes how the event loop handles it.

Jorge

unread,
Aug 27, 2010, 5:25:56 PM8/27/10
to nodejs
On Aug 27, 9:45 pm, Camilo Aguilar <cam...@cloudescape.com> wrote:
> Jorge, you need free your mind of paradigms when you are learning something
> new.

Yep. Maybe I have to say that I love Node? It's probably the best
thing that has happened to the web since Brendan put JavaScript in
NN2.

> Do you know what we want to say with event loop in nodejs?. Nodejs
> isn't a browser. The head of any web programmer has to understand that
> process.nextTick in Nodejs is the best way in performance terms.

But that's so just because setTimeout(,0) is a bit botched.

> leave setTimeout in the browser and use nextTick in nodejs. They are
> complete different in implementation in nodejs.

nextTick is wonderful. But setTimeout's implementation is botched for
0ms.

And, don't you think that the more familiar the node syntax is, the
better ?

E.g., eventEmitter.on('event', handler) is OK (much much better than
the long and ugly w3 DOM's API names) but it could have been as well
eventEmitter.addEventListener("event", handler), and I think that in
fact I've seen it aliased somewhere: http://github.com/ry/node/blob/master/src/node.js#L544
:

process.on = process.addListener = function (type, listener) {

But why to alias it to addListener instead of addEventListener, which
is what we're all used to ? I can see myself typing it wrong every now
and then, because it's not what I'm used to. So now we've got 4 ways
to say the same thing: .on, .addListener, .addEventListener
and .attachEvent... :-))
--
Jorge.

Isaac Schlueter

unread,
Aug 27, 2010, 5:40:45 PM8/27/10
to nod...@googlegroups.com
Bug: callNext doesn't set "this". Here's a patch:

- function applyNext(fn, args, thisp) {
+ function applyNext(fn, thisp, args) {


process.nextTick(function () {
fn.apply(thisp, args);
});
}

function callNext(fn, thisp) {
- applyNext(fn, Array.prototype.slice.call(arguments, 1));
+ applyNext(fn, thisp, Array.prototype.slice.call(arguments, 2));
}

--i

Vitali Lovich

unread,
Aug 27, 2010, 5:49:17 PM8/27/10
to nod...@googlegroups.com
I concur - it makes a lot of sense to optimize the case of 0 for
setTimeout & setInterval - there's nothing in the semantics that
mandates that it actually gets implemented as a timer (not to mention
that expected behaviour is that it's not).

The only thing you have to be careful with is that
setTimeout/setInterval still returns an id that can be cancelled with
clearTimeout (e.g. recall things added with nextTick). Otherwise you
break semantics in a surprising way.

-Vitali

Brian Mitchell

unread,
Aug 27, 2010, 6:01:34 PM8/27/10
to nod...@googlegroups.com
>     applyNext(console.log, ["Hello World"]);
>     process.nextTick(hello.bind(this, "world"));
>     process.nextTick(console.log, "hello ", x);

These are obviously simple examples. The truth for mine being that I'm
passing an arg to something else so it just as well could bind
console.log. We do lose some ()'s which is nice, though we still don't
have the ability to bind `this` if that was important. I feel like
this method of argument passing is somewhat outdated now that ES-5 is
taking hold and V8 has started supporting an array of the extensions.
Granted, bind is a little verbose, but there aren't many cases when I
want to pass state and I'm not using a closure or an object for that
state. Threading arguments through calls has always been an annoyance
(I'll blame Haskell for making me picky here with its do syntax).

I'd be fine with seeing these extensions go in provided it doesn't
have a negative impact on performance (not that I have any final word
to say). I do not see myself using them.

Brian.

Eugene Lazutkin

unread,
Aug 27, 2010, 6:12:33 PM8/27/10
to nod...@googlegroups.com
setTimeout(, 0) is a hack. Even in the browser it doesn't work as
intended. No need to patch it, when there is a clean alternative:
setTimeout() schedules a function after some delay, nextTick() schedules
a function as soon as possible.

My understanding that this special role of setTimeout(,0) is an
important part of your belief system => it is a religious question,
which cannot be resolved by a debate.

Nobody can prevent you from using setTimeout(,0) as you please, and if
you want you can clone the project in Github, and change it as you
please too => your implementation will be superior => people will
abandon Node.js and flock to your clone. ;-) There is nothing to discuss
here.

Cheers,

Eugene Lazutkin
http://lazutkin.com/

Vitali Lovich

unread,
Aug 27, 2010, 10:25:39 PM8/27/10
to nod...@googlegroups.com
Eugene please don't jump into a discussion for the purposes of
starting a flame-war. There's no need to even fork - it's trival to
write a wrapper within js that accomplishes this application-wide.
This is a discussion about improving node.js for everyone
transparently.

I have yet to see a good technical reason how setTimeout(, 0) is
expected to have different semantics & why an improvement for it is
not warranted.

Here are the criteria I feel need to be addressed on this topic:
1) Is any current functionality broken by changing this implementation
2) Is the broken functionality perfectly correct code or is it making
assumptions about internal implementation that was never documented.
3) Is the broken functionality in any really visible components?
4) Are the performance benefits likely to be felt wide-spread?

Here's what has been so far:
#1 setTimeout/setInterval returns a cancellable handle - any
optimization via nextTick *must* address this issue. I would prefer
that this solve the issue properly instead of delegating to a wrapper
function that checks whether or not it was cancelled.
#2 is only for code that cancel's said timeout - no expectation on the
relative ordering between setTimeout/setInterval & nextTick is
allowed.
#3 unclear
#4 is yes since many people may write code expecting setTimeout(, 0)
to behave optimally (& there's no reason it shouldn't).

#1 may mean prove to be too difficult to implement cleanly (one
alternative would be to allow a configurable property - e.g.
setTimeout0Turbo(true), although I'm not enamoured with that
particular idea either).

-Vitali

Eugene Lazutkin

unread,
Aug 27, 2010, 11:23:13 PM8/27/10
to nod...@googlegroups.com
Vitaly, no need to get defensive. This "discussion" clogged my mailbox
and so far no end in sight is expected. I don't want to fan a flame war
(it goes on without me --- count posts), I ask politely to cork it.

This "problem" is not the most pressing issue with node.js, frankly it
is fairly unimportant by any masure, and I don't see principals leaning
towards "fixing" it --- why waste time? Clone the repo, fix it,
demonstrate that it is superior and be done with it.

Cheers,

Eugene Lazutkin
http://lazutkin.com/

Marco Rogers

unread,
Aug 27, 2010, 11:36:38 PM8/27/10
to nod...@googlegroups.com
Sooo, you want us to stop having an interesting conversation about node on a public mailing list created for that purpose, because you decided to get full emails instead of a digest?  You'll excuse me if I politely decline.

Cheers
:Marco

Timothy Caswell

unread,
Aug 27, 2010, 11:39:26 PM8/27/10
to nod...@googlegroups.com

On Aug 27, 2010, at 7:25 PM, Vitali Lovich wrote:

> Eugene please don't jump into a discussion for the purposes of
> starting a flame-war. There's no need to even fork - it's trival to
> write a wrapper within js that accomplishes this application-wide.
> This is a discussion about improving node.js for everyone
> transparently.
>
> I have yet to see a good technical reason how setTimeout(, 0) is
> expected to have different semantics & why an improvement for it is
> not warranted.
>
> Here are the criteria I feel need to be addressed on this topic:
> 1) Is any current functionality broken by changing this implementation

Yes, it breaks semantics if setTimeout fires faster than it does currently. nextTick events are higher priority than timeout events. It's part of node. Changing that would change node and break programs that expect the old behavior.

> 2) Is the broken functionality perfectly correct code or is it making
> assumptions about internal implementation that was never documented.

I think it was documented that process.nextTick has a special place of high priority in the event queue. I know Ryan has said this. From the docs:

> On the next loop around the event loop call this callback. This is not a simple alias to setTimeout(fn, 0), it's much more efficient.


> 3) Is the broken functionality in any really visible components?

Not sure what you mean by this. setTimeout and process.nextTick aren't the same thing.

> 4) Are the performance benefits likely to be felt wide-spread?

Again, I'm not sure what you're asking. People wanting to defer something to the next tick as fast as possible will already be using nextTick. Someone wanting to set a timeout till after a specified time will use setTimeout.

Using setTimeout with a 0 timeout is a very bad idea in most cases. It's rarely the intended effect.

>
> Here's what has been so far:
> #1 setTimeout/setInterval returns a cancellable handle - any
> optimization via nextTick *must* address this issue. I would prefer
> that this solve the issue properly instead of delegating to a wrapper
> function that checks whether or not it was cancelled.

> #2 is only for code that cancel's said timeout - no expectation on the
> relative ordering between setTimeout/setInterval & nextTick is
> allowed.
> #3 unclear
> #4 is yes since many people may write code expecting setTimeout(, 0)
> to behave optimally (& there's no reason it shouldn't).
>
> #1 may mean prove to be too difficult to implement cleanly (one
> alternative would be to allow a configurable property - e.g.
> setTimeout0Turbo(true), although I'm not enamoured with that
> particular idea either).

setTimeout0Turbo(true)? what's wrong with the current simple and very clear API? A timeout is a timeout, pushing something to the next is called nextTick.

I'm all for API's being simple and clean, and before I fully understood the meaning of nextTick I too was fighting to just merge it with setTimeout. Now I realize they are very different things and should stay that way for sanity's sake.

>
> -Vitali
>

Eugene Lazutkin

unread,
Aug 27, 2010, 11:51:08 PM8/27/10
to nod...@googlegroups.com
Short memory? I was asked "don't jump into a discussion" --- just read
below. I politely decline your polite decline.

Cheers,

Eugene Lazutkin
http://lazutkin.com/

On 08/27/2010 10:36 PM, Marco Rogers wrote:
> Sooo, you want us to stop having an interesting conversation about node
> on a public mailing list created for that purpose, because you decided
> to get full emails instead of a digest? You'll excuse me if I politely
> decline.
>
> Cheers
> :Marco
>
>
> On Fri, Aug 27, 2010 at 11:23 PM, Eugene Lazutkin
> <eugene....@gmail.com

> <mailto:eugene....@gmail.com>> wrote:
> >> setTimeout(, 0) is a hack. Even in the browser it doesn't work as
> >> intended. No need to patch it, when there is a clean alternative:
> >> setTimeout() schedules a function after some delay, nextTick()
> schedules
> >> a function as soon as possible.
> >>
> >> My understanding that this special role of setTimeout(,0) is an
> >> important part of your belief system => it is a religious question,
> >> which cannot be resolved by a debate.
> >>
> >> Nobody can prevent you from using setTimeout(,0) as you please,
> and if
> >> you want you can clone the project in Github, and change it as you
> >> please too => your implementation will be superior => people will
> >> abandon Node.js and flock to your clone. ;-) There is nothing to
> discuss
> >> here.
> >>
> >> Cheers,
> >>
> >> Eugene Lazutkin
> >> http://lazutkin.com/
> >>
> >>
> >> On 08/27/2010 04:25 PM, Jorge wrote:
> >>> On Aug 27, 9:45 pm, Camilo Aguilar
> <cam...@cloudescape.com

> <mailto:nod...@googlegroups.com>.


> >> To unsubscribe from this group, send email to
> nodejs+un...@googlegroups.com

> <mailto:nodejs%2Bunsu...@googlegroups.com>.


> >> For more options, visit this group at
> http://groups.google.com/group/nodejs?hl=en.
> >>
> >>
> >
>
> --
> You received this message because you are subscribed to the Google
> Groups "nodejs" group.
> To post to this group, send email to
> nod...@googlegroups.com

> <mailto:nod...@googlegroups.com>.


> To unsubscribe from this group, send email to
> nodejs+un...@googlegroups.com

> <mailto:nodejs%2Bunsu...@googlegroups.com>.


> For more options, visit this group at
> http://groups.google.com/group/nodejs?hl=en.
>
>
>
>
> --
> Marco Rogers
> marco....@gmail.com

> <mailto:marco....@gmail.com>


>
> Life is ten percent what happens to you and ninety percent how you
> respond to it.
> - Lou Holtz
>

Eugene Lazutkin

unread,
Aug 27, 2010, 11:53:42 PM8/27/10
to nod...@googlegroups.com
BTW, if setTimeout() functionality is broken --- is there a definition
of such functionality? What is a measure stick? Personally I don't see
it broken in any way with and without taking nextTick() into consideration.

Cheers,

Eugene Lazutkin
http://lazutkin.com/

Ricardo Tomasi

unread,
Aug 28, 2010, 5:16:34 AM8/28/10
to nodejs
on node:

var write = function(str){
return function(){
console.log(str);
};
};

setTimeout(write('a'), 0);
setTimeout(write('b'), 0);
setTimeout(write('c'), 0);

=> a, b, c

setTimeout(write('a'), 0);
setTimeout(write('b'), 1);
setTimeout(write('c'), 0);

=> a, c, b
*(a, b, c on the browser - saf5. I bet 0, 10, 0 in IE keeps the
ordering too)

setTimeout(write('a'), 0);
process.nextTick(write('b'));
setTimeout(write('c'), 0);

=> b, a, c

That's different semantics, you can't do that with setTimeout.
Changing it will break apps and expectations.

cheers,
Ricardo

Jorge

unread,
Aug 28, 2010, 5:49:53 AM8/28/10
to nodejs
On Aug 28, 5:39 am, Timothy Caswell <t...@creationix.com> wrote:
> (...)
> Yes, it breaks semantics if setTimeout fires faster than it does currently.  nextTick events are higher priority than timeout events.  It's part of node.  Changing that would change node and break programs that expect the old behavior. (...)

That could be preserved easily.
--
Jorge.

Camilo Aguilar

unread,
Aug 28, 2010, 10:57:34 AM8/28/10
to nod...@googlegroups.com
I'm totally agree with Eugene, setTimeout(, 0) is definitely a hack. 

> But that's so just because setTimeout(,0) is a bit botched.
>nextTick is wonderful. But setTimeout's implementation is botched for
>0ms.


Ok, you are free to hack node_timer.cc to make this better and send us a patch :)


>And, don't you think that the more familiar the node syntax is, the
>better ?

>E.g., eventEmitter.on('event', handler) is OK (much much better than
>the long and ugly w3 DOM's API names) but it could have been as well
>eventEmitter.addEventListener("event", handler), and I think that in
>fact I've seen it aliased somewhere: http://github.com/ry/node/blob/master/src/node.js#L544
>:
>
>process.on = process.addListener = function (type, listener) {
>
>But why to alias it to addListener instead of addEventListener, which
>is what we're all used to ? I can see myself typing it wrong every now
>and then, because it's not what I'm used to. So now we've got 4 ways
>to say the same thing: .on, .addListener, .addEventListener
>and .attachEvent... :-))

hum, I like to think that we can design a beautiful, concise and consistent API but certainly NodeJS doesn't have DOM objects so don't expect the same semantics.

(btw, I'm not totally agree with the name of *sync methods in NodeJS. A convention would have been better, maybe if the function receive a callback then nodejs works async otherwise sync, but this is subject of another discussion).


--
Jorge.

Camilo Aguilar

unread,
Aug 28, 2010, 11:23:36 AM8/28/10
to nod...@googlegroups.com
> But that's so just because setTimeout(,0) is a bit botched.
>nextTick is wonderful. But setTimeout's implementation is botched for
>0ms.


> Ok, you are free to hack node_timer.cc to make this better and send us a patch :)
But whatever you do in node_timer.cc, nextTick always will be more efficient, because it calls the function in the next tick of the event loop, instead of waiting for a timer. That said, I'm pretty sure that setTimeout's implementation isn't botched as you said.

Jorge

unread,
Aug 28, 2010, 11:43:13 AM8/28/10
to nodejs
On Aug 28, 5:23 pm, Camilo Aguilar <cam...@cloudescape.com> wrote:
> > But that's so just because setTimeout(,0) is a bit botched.
> >nextTick is wonderful. But setTimeout's implementation is botched for
> >0ms.
> > Ok, you are free to hack node_timer.cc to make this better and send us a
>
> patch :)
>
> But whatever you do in node_timer.cc, nextTick always will be more
> efficient, because it calls the function in the next tick of the event loop,
> instead of waiting for a timer. That said, I'm pretty sure that setTimeout's
> implementation isn't botched as you said.

I think that there's no need to create a new process.Timer() to time
0ms. What nextTick does is the proper thing to do in that case. It's
in this sense that I think that it's "a bit botched".
--
Jorge.

Ricardo Tomasi

unread,
Aug 28, 2010, 4:41:41 PM8/28/10
to nodejs
Jorge,

You must be joking ;)

The definition of setTimeout is "Schedules a timeout to run handler
after timeout milliseconds", and that's obvious from it's naming.
Making setTimeout(,0) _not_ schedule a timer doesn't make any sense.
You want to deviate an implementation from the spec just so you can
keep using what you *think* is the same function. Here is setTimeout
in the HTML5 spec:

The setTimeout() method must run the following steps:
- Let handle be a user-agent-defined integer that is greater than zero
that will identify the timeout to be set by this call.
- Add an entry to the list of active timeouts for handle.
- Get the timed task handle in the list of active timeouts, and let
task be the result.
- Get the timeout, and let timeout be the result.
- ** If the currently running task is a task that was created by the
setTimeout() method, and timeout is less than 4, then increase timeout
to 4. **
- Return handle, and then continue running this algorithm
asynchronously.-
- If the method context is a Window object, wait until the Document
associated with the method context has been fully active for a further
timeout milliseconds (not - necessarily consecutively).
- Otherwise, if the method context is a WorkerUtils object, wait until
timeout milliseconds have passed with the worker not suspended (not
necessarily consecutively).
- Otherwise, act as described in the specification that defines that
the WindowTimers interface is implemented by some other object.
- Wait until any invocations of this algorithm started before this one
whose timeout is equal to or less than this one's have completed.
- Queue the task task.

I's almost unrelated to the server-side specific nextTick(). Timers on
browsers also have a lot of other quirks, i.e. timing accuracy and
execution order are not guaranteed. Read up on timers (http://
www.whatwg.org/specs/web-apps/current-work/multipage/timers.html) and
the browser's event loop (http://www.whatwg.org/specs/web-apps/current-
work/multipage/webappapis.html#event-loop), you'll see it's a
completely different environment.

That said, I'm surprised this topic has come this far, considering it
began with a coding error.

Bradley Meck

unread,
Aug 29, 2010, 8:59:24 AM8/29/10
to nodejs
I will once again point out. nextTick preempts events. setTimeout(f,0)
would preempt events always with the suggestion, this is an amazingly
large edge case for the optimization when setTimeout(f,1) would never
preempt an event.
> execution order are not guaranteed. Read up on timers (http://www.whatwg.org/specs/web-apps/current-work/multipage/timers.html) and

Jorge

unread,
Aug 29, 2010, 3:45:30 PM8/29/10
to nodejs
On Aug 27, 10:59 pm, Jorge <jo...@jorgechamorro.com> wrote:
>
> In any case, as talk is cheap, I'll see what code -if any- can I come up with, so that we have something more concrete to discuss.

Ok. Here is my proposal: http://github.com/xk/node/commit/ba472db0ca5496f6bd6ead119cf1c710cd4d590b

The tests at http://github.com/xk/nodeSnippets/blob/master/nextTick_vs_setTimeout.js
now give :

nextTick: [401.59 KHz], setTimeout: [401.59 KHz]

instead of (see http://groups.google.com/group/nodejs/browse_thread/thread/b564ac42ac53e424/7b85530b465f578d#7b85530b465f578d)

nextTick: [174.79 KHz], setTimeout: [174.79 KHz]

PATCH: Timers and NextTick

-nextTick() now returns a reference that can be used to remove it.
-Use process.rmvNextTick to remove a nextTick
-setTimeouts and setIntervals remain exactly as they were before
except for delays of 0ms
-setTimeout(,0) is now handled as a nextTick behind the scenes (but
one that accepts params to the callback)
-setInterval(,0) is also handled as a nextTick behind the scenes (good
for 100% cpu usage, accepts params to the callback)
-free-running speed of a nextTick loop has been increased slightly due
to the removal of a try { }.
-free-running speed of a setTimeout(,0) loop has been increased
vastly: more that 2x.
-A callback that throws won't break anything (didn't need a try there,
istm).
-Lots of comments.

I hope you like it !
--
Jorge
Message has been deleted

Vitali Lovich

unread,
Aug 29, 2010, 8:23:29 PM8/29/10
to nod...@googlegroups.com
I'd prefer it called process.removeNextTick - I think it makes sense
to keep this legible.
I also don't like the way removeNextTick is implemented - indexOf
means you're doing an expensive array search just to find the element
you want to remove & removing from an array means you're shifting
elements around which is expensive.

My preferred idea would be to either figure out some way of storing it
in a map so that it's O(1) to insert & remove or store the index as
part of the object you return from nextTick & then updating all the
indexes through the array element references on removal (less ideal).

Vitali Lovich

unread,
Aug 29, 2010, 8:30:37 PM8/29/10
to nod...@googlegroups.com
Oh, & just another idea - how about maintaining the setTimeout stuff
on a separate nextTick queue that gets invoked after the ones that
call nextTick directly - that'll maintain the current behaviour &
pre-empt those people complaining that this somehow drastically alters
semantics (not that I'm convinced that nextTick nor setTimeout provide
any guarantees about the order of callbacks invoked when the timeout
is the same).

-Vitali

Isaac Schlueter

unread,
Aug 29, 2010, 8:33:19 PM8/29/10
to nod...@googlegroups.com
I think nextTick shouldn't be removeable. It should be like a
function call. You can't un-call a function.

Vitali Lovich

unread,
Aug 29, 2010, 8:32:38 PM8/29/10
to nod...@googlegroups.com
I have a tough time understanding what you are trying to say here.
What do you mean by pre-empts because it's probably drastically
different than mine.

Scott González

unread,
Aug 29, 2010, 8:45:21 PM8/29/10
to nod...@googlegroups.com
I'm in agreement with Isaac, nextTick is generally for splitting up
code specifically to keep it non-blocking. Timeouts and intervals have
very different use cases which actually warrant being cancelable.

Vitali Lovich

unread,
Aug 29, 2010, 8:46:12 PM8/29/10
to nod...@googlegroups.com
nextTick is a deferred function call and you can definitely cancel a
future invocation. Whether or not it should be exposed to the user is
a debatable question I have no opinion on.

2010/8/29 Scott González <scott.g...@gmail.com>:

Camilo Aguilar

unread,
Aug 29, 2010, 8:52:35 PM8/29/10
to nod...@googlegroups.com
I think that the setTimeout(,0) hack to invoke a function with similar semantics to nextTick doesn't deserve all this effort when we have nextTick already. 

Vitali Lovich

unread,
Aug 29, 2010, 9:24:33 PM8/29/10
to nod...@googlegroups.com
What do you mean by all this effort? Jorge has already graciously
provided a patch that addresses this issue - the work has been done.
The only question should be on the merits of the patch:

1) Does it significantly complicate code for no benefit
2) Does it break existing functionality
3) Is the code legible & meet qualitative standards (e.g. spaghetti
code or well-written & well-designed code)

I think there's nothing fundamentally wrong with the patch - it just
needs some minor tweaks & a more thorough code review.

-Vitali

Camilo Aguilar

unread,
Aug 29, 2010, 9:29:41 PM8/29/10
to nod...@googlegroups.com
what issue ? 

Vitali Lovich

unread,
Aug 29, 2010, 9:41:12 PM8/29/10
to nod...@googlegroups.com
That setTimeout(f, 0) can be optimized to perform significantly better
than it currently does.

Camilo Aguilar

unread,
Aug 29, 2010, 10:01:08 PM8/29/10
to nod...@googlegroups.com
omg, I will leave this discussion here. setTimeout(f, 0) is a hack. In nodejs nextTick is the clean way.

Tim Caswell

unread,
Aug 29, 2010, 10:36:12 PM8/29/10
to nod...@googlegroups.com

Why complicate the code for a use case that shouldn't exist?  Namely using setTimeout when you really mean nextTick.

Even if someone provides a patch it still has to be maintained.  This is not without cost and very little gain if any.

Sent from my Nexus One

Jorge

unread,
Aug 30, 2010, 5:38:13 AM8/30/10
to nod...@googlegroups.com
On 30/08/2010, at 02:23, Vitali Lovich wrote:

> I'd prefer it called process.removeNextTick - I think it makes sense
> to keep this legible.

No problem. It's that I like the C standard library's naming-style : rmvNxtTick :-)

nextTick items can be removed too with clearInterval/timeout(item) which is already exposed/public (but a bit slower) than removeNextTick.

> I also don't like the way removeNextTick is implemented - indexOf
> means you're doing an expensive array search just to find the element
> you want to remove & removing from an array means you're shifting
> elements around which is expensive.

No, no, Look again. I'm not removing it I just modify the item to be a nop item. You can't splice the array there because if you do you won't be able to call removeNextTick from within a callback: it would break ._tickCallback.

> My preferred idea would be to either figure out some way of storing it
> in a map so that it's O(1) to insert & remove or store the index as
> part of the object you return from nextTick & then updating all the
> indexes through the array element references on removal (less ideal).

When I thought about this I decided to favour items insertion and . _tickCallback speed over that of removeNextTick, because, istm it is not something that is going to/should be done very often. But talk is cheap, show me the code :-) . If you've got a better way, sure, let's just do it better !

KTHKS for your comments.
--
Jorge.

Jorge

unread,
Aug 30, 2010, 5:45:51 AM8/30/10
to nod...@googlegroups.com
On 30/08/2010, at 02:30, Vitali Lovich wrote:

> Oh, & just another idea - how about maintaining the setTimeout stuff
> on a separate nextTick queue that gets invoked after the ones that
> call nextTick directly - that'll maintain the current behaviour &
> pre-empt those people complaining that this somehow drastically alters
> semantics (not that I'm convinced that nextTick nor setTimeout provide
> any guarantees about the order of callbacks invoked when the timeout
> is the same).

Yep. We'd just need a separate timersQueue [] for that, and another loop just after the one that's already there in . _tickCallback. I've not done it because in my mind, still, setTimeout(,0) ought to be === nextTick... :-)

But even that wouldn't satisfy Bradley Meck :-), if, as he says, it's true that in the event loop the events queue is dispatched *after* . _tickCallback...
--
Jorge.

Jorge

unread,
Aug 30, 2010, 5:55:22 AM8/30/10
to nodejs
On Aug 30, 11:45 am, Jorge <jo...@jorgechamorro.com> wrote:
>
> But even that wouldn't satisfy Bradley Meck :-), if, as he says, it's true that in the event loop the events queue is dispatched *after* . _tickCallback...

...and *before* the timers' callbacks ?
--
Jorge.

Vitali Lovich

unread,
Aug 30, 2010, 6:29:31 AM8/30/10
to nod...@googlegroups.com
On Mon, Aug 30, 2010 at 2:38 AM, Jorge <jo...@jorgechamorro.com> wrote:
> On 30/08/2010, at 02:23, Vitali Lovich wrote:
>
>> I'd prefer it called process.removeNextTick - I think it makes sense
>> to keep this legible.
>
> No problem. It's that I like the C standard library's naming-style : rmvNxtTick :-)
I like C naming convention but it would be rmv_next_tick :D.
Javascript convention is different though.

>
> nextTick items can be removed too with clearInterval/timeout(item) which is already exposed/public (but a bit slower) than removeNextTick.

Yup - saw that.

>
>> I also don't like the way removeNextTick is implemented - indexOf
>> means you're doing an expensive array search just to find the element
>> you want to remove & removing from an array means you're shifting
>> elements around which is expensive.
>
> No, no, Look again. I'm not removing it I just modify the item to be a nop item. You can't splice the array there because if you do you won't be able to call removeNextTick from within a callback: it would break ._tickCallback.

Good point. I need to look over the patch again, but does that mean
the array is never gc'ed?

>
>> My preferred idea would be to either figure out some way of storing it
>> in a map so that it's O(1) to insert & remove or store the index as
>> part of the object you return from nextTick & then updating all the
>> indexes through the array element references on removal (less ideal).
>
> When I thought about this I decided to favour items insertion and . _tickCallback speed over that of removeNextTick, because, istm it is not something that is going to/should be done very often. But talk is cheap, show me the code :-) . If you've got a better way, sure, let's just do it better !

You're right on this except that clearInterval will be a common use
case (typical approach is to do setInterval(f, 0) & clear it once it
is done - something to think about.

Vitali Lovich

unread,
Aug 30, 2010, 6:31:22 AM8/30/10
to nod...@googlegroups.com
Sorry - so is the current ordering nextTick, events, setTimeout(f, 0)?

Also, I really dislike this implicit arbitrary ordering that's being
imposed on async callbacks.

Vitali Lovich

unread,
Aug 30, 2010, 6:35:03 AM8/30/10
to nod...@googlegroups.com
On Sun, Aug 29, 2010 at 7:36 PM, Tim Caswell <t...@creationix.com> wrote:
> Why complicate the code for a use case that shouldn't exist?  Namely using
> setTimeout when you really mean nextTick.
>
> Even if someone provides a patch it still has to be maintained.
No individual patch is ever maintained - the project is, as a whole.
Thus you determine whether a patch makes a project unmaintainable (or
contributes to that in some way) - not whether or not someone will be
continuously monitoring a single patch for the lifetime it exists.

>  This is not
> without cost and very little gain if any.

There is significant gain - there are people trying to write code that
is common to both node & the web. Browsers don't have a concept of
nextTick, but do for setTimeout. If you can reduce & isolate the
node-isms (or remove them where unnecessary such as here), it makes it
a lot easier for them.

Jorge

unread,
Aug 30, 2010, 6:48:07 AM8/30/10
to nod...@googlegroups.com
On 30/08/2010, at 12:31, Vitali Lovich wrote:

> Sorry - so is the current ordering nextTick, events, setTimeout(f, 0)?

That's what I understand in Bradley Mecks' message:

"I will once again point out. nextTick preempts events. setTimeout(f,0)
would preempt events always with the suggestion, this is an amazingly
large edge case for the optimization when setTimeout(f,1) would never
preempt an event."

I wanted to test it, but found out that eventEmitter.emit(event) is synchronous.

Is there a queue event ?
And if there is, shouldn't eventEmitter.emit() just push an event into that queue ?

> Also, I really dislike this implicit arbitrary ordering that's being
> imposed on async callbacks.

What do you mean ?
--
Jorge.

Vitali Lovich

unread,
Aug 30, 2010, 7:38:15 AM8/30/10
to nod...@googlegroups.com
Just that they're trying to imply some relative ordering about
nextTicks, events, & setTimeouts that appear arbitrary without any
good reason - async callbacks are async for a reason - they can occur
in any order.

eventEmitter.emit should be synchronous. For example, I would expect
to call process.emit('exit') right before I call process.exit.
Similar idea for any other example. That is the typical way signals
invoke slots (typically only do deferred invocation for slots that
exist on other threads to avoid thread-safety issues).

Jorge

unread,
Aug 30, 2010, 7:49:50 AM8/30/10
to nodejs
On Aug 30, 12:29 pm, Vitali Lovich <vlov...@gmail.com> wrote:
> On Mon, Aug 30, 2010 at 2:38 AM, Jorge <jo...@jorgechamorro.com> wrote:
> > On 30/08/2010, at 02:23, Vitali Lovich wrote:
>
> >> I'd prefer it called process.removeNextTick - I think it makes sense
> >> to keep this legible.
>
> > No problem. It's that I like the C standard library's naming-style : rmvNxtTick :-)
>
> I like C naming convention but it would be rmv_next_tick :D.
> Javascript convention is different though.

clearTimeout, clearInterval and *clear*NextTick, then ?

> > nextTick items can be removed too with clearInterval/timeout(item) which is already exposed/public (but a bit slower) than removeNextTick.
>
> Yup - saw that.

Should we expose remove/clearNextTick too, or just clearInterval/
timeout would do ?

> >> I also don't like the way removeNextTick is implemented - indexOf
> >> means you're doing an expensive array search just to find the element
> >> you want to remove & removing from an array means you're shifting
> >> elements around which is expensive.
>
> > No, no, Look again. I'm not removing it I just modify the item to be a nop item. You can't splice the array there because if you do you won't be able to call removeNextTick from within a callback: it would break ._tickCallback.
>
> Good point.  I need to look over the patch again, but does that mean
> the array is never gc'ed?

I hope not !

> >> My preferred idea would be to either figure out some way of storing it
> >> in a map so that it's O(1) to insert & remove or store the index as
> >> part of the object you return from nextTick & then updating all the
> >> indexes through the array element references on removal (less ideal).
>
> > When I thought about this I decided to favour items insertion and . _tickCallback speed over that of removeNextTick, because, istm it is not something that is going to/should be done very often. But talk is cheap, show me the code :-) . If you've got a better way, sure, let's just do it better !
>
> You're right on this except that clearInterval will be a common use
> case (typical approach is to do setInterval(f, 0) & clear it once it
> is done - something to think about.

A setInterval(,0) isn't a bit too much ? :

$ node
Type '.help' for options.
node> function f () {}
node> setInterval(f,0)
[ [Function] ]
node>

$ top
...
PID COMMAND %CPU TIME ..
44851 node 99. 90 ...

BTW, another bug (?) : typing .exit above at the node repl doesn't
quit... neither does this:
$ node
Type '.help' for options.
node> process.nextTick(function f () { process.nextTick(f) })
[ [Function] ]
node> .exit

:-)
--
Jorge.

Vitali Lovich

unread,
Aug 30, 2010, 8:03:42 AM8/30/10
to nod...@googlegroups.com
Try process.exit instead - not sure what .exit does on the command line (my try to schedule an idle event, which will never happen since there's going to always be something in the event loop).

clearNextTick is a good name.  I don't have an opinion on whether to expose it or not.  Ask Ryan.

Regarding setInterval, I was thinking more this:

var worker;
function processWork()
{
  if (!moreWork()) {
    clearInterval(worker);
  }
  var workItem = popWorkItem();
}
setInterval(worker, 0);

Jorge.

Jorge

unread,
Aug 30, 2010, 9:09:24 AM8/30/10
to nod...@googlegroups.com
On 30/08/2010, at 14:03, Vitali Lovich wrote:

> Try process.exit instead - not sure what .exit does on the command line (my try to schedule an idle event, which will never happen since there's going to always be something in the event loop).

The repl .exit is doing a self.stream.destroy(); (stream being process.stdin, istm) which will kill the repl, but not necessarily node.

Maybe there should be a .quit that called process.exit() ?
or a just process.exit() after the stream.destroy() would do ?

http://github.com/xk/node/commit/be12c250e544e99681b27bc7b8844fb3db4d4d29
--
Jorge.


Jorge

unread,
Aug 30, 2010, 9:25:20 AM8/30/10
to nod...@googlegroups.com
On 30/08/2010, at 13:38, Vitali Lovich wrote:
> On Mon, Aug 30, 2010 at 3:48 AM, Jorge <jo...@jorgechamorro.com> wrote:
>> On 30/08/2010, at 12:31, Vitali Lovich wrote:
>>
>>> Sorry - so is the current ordering nextTick, events, setTimeout(f, 0)?
>>
>> That's what I understand in Bradley Mecks' message:
>>
>> "I will once again point out. nextTick preempts events. setTimeout(f,0)
>> would preempt events always with the suggestion, this is an amazingly
>> large edge case for the optimization when setTimeout(f,1) would never
>> preempt an event."
>>
>> I wanted to test it, but found out that eventEmitter.emit(event) is synchronous.
>>
>> Is there a queue event ?
>> And if there is, shouldn't eventEmitter.emit() just push an event into that queue ?
>>
>>> Also, I really dislike this implicit arbitrary ordering that's being
>>> imposed on async callbacks.
>>
>> What do you mean ?
>
>
> Just that they're trying to imply some relative ordering about
> nextTicks, events, & setTimeouts that appear arbitrary without any
> good reason - async callbacks are async for a reason - they can occur
> in any order.
>
> eventEmitter.emit should be synchronous. For example, I would expect
> to call process.emit('exit') right before I call process.exit.
> Similar idea for any other example. That is the typical way signals
> invoke slots (typically only do deferred invocation for slots that
> exist on other threads to avoid thread-safety issues).

Say you've got this:

var in10seconds= Date.now()+ 10e3;
while ( Date.now() < in10seconds ) ; //don't ever do this :-)

And during that 10 seconds some packets arrive, a file chunk is read, and etc ..., things that generate say 5 events while the program is in that 10 seconds loop.

1.- You don't expect these events to interrupt the loop, because they're events, not interrupts.
2.- You'd expect them to be handled in the order that they happened. For that there's an -fifo- event queue, right ?

Now, say that the line right after that loop were:

process.emit("someEvent");

Why would you expect that "someEvent" event to be handled *before* the ones that were already pending ?

I'd say you should not expect that to be so.

Which is no to say that sometimes you might want an event to be handled synchronously, but then it's not really behaving as an "event", but more like an interrupt.

Don't you think so ?
--
Jorge.

Jorge

unread,
Aug 30, 2010, 9:38:46 AM8/30/10
to nod...@googlegroups.com
On 30/08/2010, at 14:03, Vitali Lovich wrote:

> clearNextTick is a good name.

[x] Done

http://github.com/xk/node/commit/df1de048e4c7de861bcb38c6520462a75ab356ab

> I don't have an opinion on whether to expose it or not. Ask Ryan.

Yep. Let's see what says the boss.
--
Jorge.

Bradley Meck

unread,
Aug 30, 2010, 9:59:54 AM8/30/10
to nodejs
when talking about preemption, nextTick occurs before queued events
(all of them). and setTimeout occurs after queued events. That is a
rather large difference.

On Aug 30, 8:38 am, Jorge <jo...@jorgechamorro.com> wrote:
> On 30/08/2010, at 14:03, Vitali Lovich wrote:
>
> > clearNextTick is a good name.
>
> [x] Done
>
> http://github.com/xk/node/commit/df1de048e4c7de861bcb38c6520462a75ab3...

Dean Landolt

unread,
Aug 30, 2010, 10:32:12 AM8/30/10
to nod...@googlegroups.com
On Mon, Aug 30, 2010 at 9:59 AM, Bradley Meck <bradle...@gmail.com> wrote:
when talking about preemption, nextTick occurs before queued events
(all of them). and setTimeout occurs after queued events. That is a
rather large difference.


Sure, that's how it works now, but the important question is whether this is a feature or just an API leak? After all this is an event queue -- should you ever depend on a specific order of operations?

Marco Rogers

unread,
Aug 30, 2010, 10:32:22 AM8/30/10
to nod...@googlegroups.com
-1 to all of this.

I think nextTick and setTimeout work exactly they way they should.  In my mind, setTimout(f, 0) is an edge case but it is not a special case.  Yes it can be optimized, but I haven't heard the really compelling reason why it should.  It creates all these questionable scenarios that need to be reasoned about.  Hence the length of this thread.

As for allowing clearNextTick.  I think this is a monumentally bad idea.  One that hasn't really been needed or asked for up until this point.  It's only arising out of some sense that nextTick and setTimeout should be made more alike.  But in the process, the simplicity of both is being damaged.

The only good argument I've heard is for browser compatibility. I respect this concern. But I also think it's easily addressable outside of node core.  Nothing like nextTick exists in the browser.  Node runs on javascript, but it is not a browser environment. It has no intention of acting like one (though some are building one top of it).  So if you want your module to work in both, you will need to do some compatibility shivving in the browser.  In the case of nextTick.  This is really easy.

process = window.process || {};
process.nextTick = function(callback) {
    setTimeout(callback, 0);
}

But you still won't see analogous behavior to the kind that your patch introduces in node.  Because while some browsers have tried really hard to optimize setTimeout.  Others have purposefully handicapped it so it can't chew up the browser UI thread.  Hence even if you pass 0 to setTimeout you will get at least a 10ms delay. You can't be sure that things will happen in the same way they might happen in node.

It seems to me that in the case of setTimeout, we're as close as we are likely to get to matching semantics with the browser without introducing unnecessary complexity.  So we shouldn't try.  If you want browser compatibility, don't use nextTick at all.

:Marco


--
You received this message because you are subscribed to the Google Groups "nodejs" group.
To post to this group, send email to nod...@googlegroups.com.
To unsubscribe from this group, send email to nodejs+un...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/nodejs?hl=en.




--
Marco Rogers
marco....@gmail.com

Life is ten percent what happens to you and ninety percent how you respond to it.
- Lou Holtz

Camilo Aguilar

unread,
Aug 30, 2010, 10:36:41 AM8/30/10
to nod...@googlegroups.com
I'm completely agree with Marco and Bradley. Just for curiosity, Marco did you read http://code.google.com/p/chromium/issues/detail?id=888 ? :)

Marco Rogers

unread,
Aug 30, 2010, 10:38:21 AM8/30/10
to nod...@googlegroups.com


Sure, that's how it works now, but the important question is whether this is a feature or just an API leak? After all this is an event queue -- should you ever depend on a specific order of operations?


Yes, but only with semantically related events.  Like chunks of data coming off of a socket.  These have to be in order.  There may be other events firing that are interspersed with those data events.  That's fine and shouldn't be a problem.  But the ordering if events is significant.  The word "event" doesn't immediately presume randomness.  It just means asynchronous right?.

--
You received this message because you are subscribed to the Google Groups "nodejs" group.
To post to this group, send email to nod...@googlegroups.com.
To unsubscribe from this group, send email to nodejs+un...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/nodejs?hl=en.

Dean Landolt

unread,
Aug 30, 2010, 10:45:48 AM8/30/10
to nod...@googlegroups.com
On Mon, Aug 30, 2010 at 10:38 AM, Marco Rogers <marco....@gmail.com> wrote:


Sure, that's how it works now, but the important question is whether this is a feature or just an API leak? After all this is an event queue -- should you ever depend on a specific order of operations?


Yes, but only with semantically related events.  Like chunks of data coming off of a socket.  These have to be in order.  There may be other events firing that are interspersed with those data events.  That's fine and shouldn't be a problem.  But the ordering if events is significant.  The word "event" doesn't immediately presume randomness.  It just means asynchronous right?.

I guess the word "queue" does kinda imply order :)

Still, like you said only semantically related operations need to be ordered. I wasn't suggesting setTimeout should be optimized, I'm just curious if it should be considered safe to make the assumptions about queued events Bradley posed.

Bradley Meck

unread,
Aug 30, 2010, 11:03:52 AM8/30/10
to nodejs
if i want to run a clean up after my even loop is done ie: kill
connections that may be left open but shouldnt be, maybe.

On Aug 30, 9:32 am, Dean Landolt <d...@deanlandolt.com> wrote:

Ricardo Tomasi

unread,
Aug 30, 2010, 2:21:55 PM8/30/10
to nodejs
Since JS will remain single-threaded for the foreseeable future, I
don't see how that could change. There'll always be an order of
execution for event/timer queues, and the way it is now makes perfect
sense, IMO. You shouldn't expect a timer to fire before an event for
any reasonable logic, but the opposite is true for nextTick since it's
supposed to run 'as soon as possible' - it implies awareness of an
event loop, which setTimeout doesn't.

On 30 ago, 11:32, Dean Landolt <d...@deanlandolt.com> wrote:

Vitali Lovich

unread,
Aug 30, 2010, 2:26:33 PM8/30/10
to nod...@googlegroups.com
> 1.- You don't expect these events to interrupt the loop, because they're events, not interrupts.
I'd expect them not to interrupt the loop because Javascript is single-threaded. There's no way to interrupt any statement.

> 2.- You'd expect them to be handled in the order that they happened. For that there's an -fifo- event queue, right ?

Right


> Now, say that the line right after that loop were:
>
> process.emit("someEvent");
>
> Why would you expect that "someEvent" event to be handled *before* the ones that were already pending ?

Because you're not emitting an event so much as a signal. Maybe it might be helpful to have a send('signal') that posts it on the event queue.

> I'd say you should not expect that to be so.
>
> Which is no to say that sometimes you might want an event to be handled synchronously, but then it's not really behaving as an "event", but more like an interrupt.

JS has no concept of interrupts - not sure what you're trying to say.


>
> Don't you think so ?

I disagree on this point.

Vitali Lovich

unread,
Aug 30, 2010, 2:42:54 PM8/30/10
to nod...@googlegroups.com
So you want node-isms to leak to browser code?  That is definitely the wrong solution.

Additionally, you yourself just posted a snippet of code that would have different ordering semantics implying that any application that can't deal with it is buggy.

As Dean correctly points out - you can't assume an event order for semantically different events just because it's the current behaviour.

Vitali Lovich

unread,
Aug 30, 2010, 2:43:36 PM8/30/10
to nod...@googlegroups.com
Bradley,wouldn't the correct approach be to do setTimeout once the events you care about have finished firing (e.g. you know your clean-up condition). I fail to see how your example can possibly even work since you don't know what events are going to be on the next loop.

Marco Rogers

unread,
Aug 30, 2010, 2:53:23 PM8/30/10
to nod...@googlegroups.com
I don't want node-isms to leak to the browser no.  It was just a suggestion of an alternative.  I think any module that's supposed to work on both sides of the wire is going to have to deal with the fact that the two environments are very different.  We're used to doing this in the browser.  And we've done this in some places in node, with setTimeout being a prime example.  It's not part of javascript proper.  But it's a very useful construct in the browser and it's generically useful in node as well *when you need a delay*.

The problem I have with this thread is that we are discussing taking those two things and producing an unholy melding.  If you cringe at putting nextTick in the browser, why do you want setTimeout to infect the custom node.js event loop?

What I'm saying is this doesn't need to go into core.  If you really want it, that's fine and you can accomplish something close to it in user-land with the simple dynamic power of javascript.

:Marco

Dean Landolt

unread,
Aug 30, 2010, 2:55:52 PM8/30/10
to nod...@googlegroups.com
On Mon, Aug 30, 2010 at 2:21 PM, Ricardo Tomasi <ricar...@gmail.com> wrote:
Since JS will remain single-threaded for the foreseeable future, I
don't see how that could change. There'll always be an order of
execution for event/timer queues, and the way it is now makes perfect
sense, IMO. You shouldn't expect a timer to fire before an event for
any reasonable logic, but the opposite is true for nextTick since it's
supposed to run 'as soon as possible' - it implies awareness of an
event loop, which setTimeout doesn't.


Thanks Ricardo...

This is the compelling argument I was looking for :)

Vitali Lovich

unread,
Aug 30, 2010, 3:08:17 PM8/30/10
to nod...@googlegroups.com
Events come in in any order and are external to the application - I don't see how you can make assumptions about when setTimeout will get called relative to events you don't know exist yet.  Am I missing something?

Vitali Lovich

unread,
Aug 30, 2010, 3:12:30 PM8/30/10
to nod...@googlegroups.com
The idea is that we can improve the performance of setTimeout - I don't see it as an unholy melding & I don't understand the strong opposition to doing this.

A timeout of 0 implies 0 delay to me.  Yet you are making assumptions that there is still just a little bit of extra delay imposed so that there's some kind of implicit ordering from the by-product of the implementation.

Marco Rogers

unread,
Aug 30, 2010, 3:29:39 PM8/30/10
to nod...@googlegroups.com
I don't mind making setTimeout faster.  But doing so involves injecting it into the event loop in the same way nextTicks are.  But setTimeouts can be cancelled as well.  Well if we're allowing that, should we do it for nextTick too?  The answer is no, IMO.  But now we have to talk endlessly about what it means that removable setTimeout events are dispersed throughout the event queue instead of being handled afterwards.  What the intended behavior should be is not clear.  This is a strong indication to me that is a bad idea.  If we do it, then  the semantics it creates will make setTimeout(f, 0) act differently in node then it does in the browser.  This is another red flag for me.

I'm not saying it's impossible to figure out how to make this a sane and useful change.  But the proposed patch is not it.  And considering all of the above, I would need a better reason to get on board with this.  The only ones I keep getting are:

1) Speed - Yes it'll be faster, but only in node.  And if you need a faster setTimeout in node, use nextTick. You get all the benefit and avoid the sticky issues above.

2) Semantic compatibility with the browser - I believe this change goes against the goal of browser compatibility.  setTimeout in the browser is always delayed.  So you're proposing a solution that would explicitly make it work differently.

That's as clear as I can make my position.  I'm not trying to brow beat anyone. After my initial reactions, I stayed out of the discussion for a while to see if a good case could be made.  I just don't think there are any clear benefits to doing this.

:Marco

Marco Rogers

unread,
Aug 30, 2010, 3:40:27 PM8/30/10
to nod...@googlegroups.com

A timeout of 0 implies 0 delay to me.  Yet you are making assumptions that there is still just a little bit of extra delay imposed so that there's some kind of implicit ordering from the by-product of the implementation.


Sorry, I think the reason for my opposition wasn't clear. I'm not trying to preserve some arbitrary ordering of things in node.  I fully agree that ideally this should be optimized.  But that's a problem with the setTimeout spec that requires timers.  And yeah, we could just go around that.  But the other barrier is that the many browser implementations of setTimeout have already given us defacto semantics.  We'd be willfully changing those in node.  That difference will create complexity in reasoning about node execution and it will trip people up. And that is worse to me then being annoyed that setTimeout(f, 0) is still slightly delayed. That's how it works in the browser.  And since setTimeout is a construct borrowed from the browser. It's not a big deal to leave it that way.  Especially since node has provided a nicer alternative.  So essentially:

Problem - setTimeout(f, 0) is still delayed. Not fast enough.

Your Solution - Let's change the semantics and optimize the 0 case.

My Solution - Use something better. Here's nextTick

:Marco

Vitali Lovich

unread,
Aug 30, 2010, 3:35:32 PM8/30/10
to nod...@googlegroups.com
On Mon, Aug 30, 2010 at 12:29 PM, Marco Rogers <marco....@gmail.com> wrote:
I don't mind making setTimeout faster.  But doing so involves injecting it into the event loop in the same way nextTicks are.  But setTimeouts can be cancelled as well.  Well if we're allowing that, should we do it for nextTick too?  The answer is no, IMO.
nextTick wouldn't be generallably cancellable, no.  Only if it was generated via setTimeout(, 0).

But now we have to talk endlessly about what it means that removable setTimeout events are dispersed throughout the event queue instead of being handled afterwards.
Sorry - I don't understand what you mean here.
 
 What the intended behavior should be is not clear.  This is a strong indication to me that is a bad idea.  If we do it, then  the semantics it creates will make setTimeout(f, 0) act differently in node then it does in the browser.  This is another red flag for me.
How do you mean? 

2) Semantic compatibility with the browser - I believe this change goes against the goal of browser compatibility.  setTimeout in the browser is always delayed.  So you're proposing a solution that would explicitly make it work differently.
Current implementation != programmer intent.  setTimeout(, 0) is a common construct to provide interactive behaviour while processing large sets of information.  The advantage is that when the same code is run under node, it simply runs faster.

Vitali Lovich

unread,
Aug 30, 2010, 3:50:11 PM8/30/10
to nod...@googlegroups.com
I'm still unclear about what semantics you are trying to preserve.  Can you give a code snippet?

--

Ricardo Tomasi

unread,
Aug 30, 2010, 5:47:23 PM8/30/10
to nodejs


On 30 ago, 16:35, Vitali Lovich <vlov...@gmail.com> wrote:
>
> Current implementation != programmer intent.  setTimeout(, 0) is a common
> construct to provide interactive behaviour while processing large sets of
> information.  The advantage is that when the same code is run under node, it
> simply runs faster.

It is used in the browser to avoid blocking the user interface. There
is no UI to block in node, so that case is irrelevant and unnecessary
server-side. What should be optimized in this case is the end user
code, not node itself. And it will already run much faster in node
(170hz vs 400hz here), i don't think anyone is going to set up 400
timers/sec.

Jorge

unread,
Aug 30, 2010, 5:56:49 PM8/30/10
to nod...@googlegroups.com

*K*Hz : 400.000 timers/second.
--
Jorge.

Vitali Lovich

unread,
Aug 30, 2010, 9:42:52 PM8/30/10
to nod...@googlegroups.com
It is used in the browser to avoid blocking period.  All events are blocked - they're not limited to UI somehow.  Think a gaming server where you need to handle low-latency responses from the clients.


--
Reply all
Reply to author
Forward
Message has been deleted
0 new messages