Answer is simple: you are adding more and more listeners as jsPerf runs your test case.
One of the most important things to remember while using jsPerf is that setup phase can and will be executed multiple times. As the result the list of listeners attached to the DOM node is growing and this in turn slows down the event dispatch.
"No return" case is run second so the list of listeners is already large and thus it is slower than "return case".
You should either unregister listeners in tear down phase or register them only once at global initialization time. Here is the fixed variant:
Also another mistake here is the classical "if you want to measure x, don't measure y".
If the OP wanted to measure function with or without return , even without realizing how futile that is, they still should not include things like jQuery.
Well, before the GP post, my takeaway was that it's better to return when using jQuery. The justification for this would have been some magic, which is the sole purpose of jQuery, slowing stuff down.
And the web being as it is, testing with jQuery might even be more useful than testing without it.
That is a common fallacy and benchmarking anti-pattern, and it really enrages me that some people look at the completely incorrect results and justify it with "I am going to be using this with jQuery so why shouldn't I add some jQuery method calls". And you are denying this despite the "fixed" js perf showing different results e.g. on chrome 29.
What I meant was that if I'm going to run a website with jQuery calls, I should absolutely test with jQuery calls. It makes no sense to claim that one should, say, always use short variable names, if one then ships with google closure.
Revision 3 revealed that it's not the `return` that made the difference -- it's the jsperf runner failing to introduce sufficient time gap between testsuites for it to "settle down"...
Isn't the idea of hellbanning that people don't realize they are? Kinda defeats the purpose if you notify them of it. If HN wanted people to know they've been silenced, they would be given an error message. So, don't tell people. It's also spamming the comment with offtopic remarks.
Using hellbans when you should be using normal bans or even temporary bans is a horrible system.
Most people that are hellbanned on HN have not at all deserved it. Ignoring spambots, I've seen perhaps two users that got a hellban for consistently problematic posts rather than a single post annoying someone. And one of those has actual mental issues.
I browse with showdead on because frankly, apart from the occasional commentspam, pretty much none of the comments I see from hellbanned users are from users who persistently make comments that would seem to justify a ban of any kind. Most of them appear to just have made a single stupid comment at some point or other that perhaps deserved some downvoting. It seems to me that hellbans are overused.
And the answer to it being overused is for people to call it out whenever a user is trying to contribute but hellbanned, and we don't agree with the ban after taking a look at their comment history.
Sure, that's the idea. The comment looks totally legit and relevant, though.
Looks like their last comment sucked, and it's easier for a mod to ban someone than to reply, “that comment sucked” and hope they get better. Mods are never perfect, they have a big job, and people can (successfully) appeal hellbans.
Not sure what previous action caused him to get hell banned but his comment was trying to contribute something to this thread. Think it would be nice to know if I was banned and still trying to contribute.
Can't really recall a single hell ban I agree with. So the fact that everyone tries to warn the posters who have been banned kind of shows it is being misused. I would prefer it only be used on spammers and intention trolls/personal attacks. On HN it gets used far more, however. So I agree with everyone who warns people, basically.
Someone named eulerphi replied to your comment, but they're "hellbanned" from Hacker News and their reply is only visible if you turn on showdead in your settings.
Allright.. So most likely, return or no return does not make any difference. Or at least that is the feeling I get from Colin's revision (3). Myth busted? Or is there another tail to the story.
Both functions return "undefined". They should be identical after JIT compilation.
The only thing I can imagine taking longer would be the compilation step itself... but I had always assumed jsPerf didn't work like this, i.e. I thought it would wrap the test code in a 'for' loop and then eval the whole loop, rather than doing the eval call inside the loop.
Is there some low level checking by the js engine to see if it should stop processing the function if there is no return?
Or, to put it another way, does adding the return explicitly tell the engine, "ok we're done here", as opposed to a small amount of processing required by the engine to determine that for itself?
Doesn't just calling return from an event equate to returning boolean false, which means you are invoking the effects of preventDefault() and stopImmediatePropagation() thus explaining why with return it's faster as the event stops bubbling immediately?
That's not quite how it works. jQuery checks specifically for false with an === comparison. It doesn't do anything like a !! on the return value to convert it to boolean true or false. It only calls stopPropagation and preventDefault when the return value is false, not just any falsy value.
I posted the jQuery code in a previous comment; take a look at that and you can see how it works.
Doesn't a return without argument return false and thus have the same effect as preventDefault()? That would explain the difference, since the events are not "bubbling up".
An empty return statement has the return value undefined which is falsy. As lukashed said jQuery most likely interprets this as false and stop propagation of the event, however using an empty function also has the return value undefined so both cases stops propagation.
> As lukashed said jQuery most likely interprets [undefined] as false and stop propagation of the event...
No, it doesn't. jQuery uses a strict test for false and does not stop propagation for other falsy return values from an event listener.
The documentation could be more clear on this point. All it says is: "Returning false from an event handler will automatically call event.stopPropagation() and event.preventDefault()."
Reading that code, it almost seems redundant at first to have a !== undefined check when the === false is already a strict comparison. But there is that assignment hidden inside the if expression. So the code is really the same as this more clearly written version:
if ( ret !== undefined ) {
event.result = ret;
if ( ret === false ) {
event.preventDefault();
event.stopPropagation();
}
}
This would also have the same effect:
if ( ret !== undefined ) {
event.result = ret;
}
if ( ret === false ) {
event.preventDefault();
event.stopPropagation();
}
These all do the same thing: set event.result only if ret is not undefined, and then call preventDefault and stopPropagation only if ret is false (and not just a falsy value).
The two functions are different, but their return values are identical. The === is comparing the return values.
Consider this example:
function onePlusOne() { return 1 + 1; }
function two() { return 2; }
alert( onePlusOne === two ); // false, not the same function
alert( onePlusOne() === two() ); // true, same value
One of the most important things to remember while using jsPerf is that setup phase can and will be executed multiple times. As the result the list of listeners attached to the DOM node is growing and this in turn slows down the event dispatch.
"No return" case is run second so the list of listeners is already large and thus it is slower than "return case".
You should either unregister listeners in tear down phase or register them only once at global initialization time. Here is the fixed variant:
http://jsperf.com/always-return-on-jquery-events/28
[also from the JavaScript VM point of view function () { } and function () { return; } are completely the same]