Re: addEvent - The late entry :)
- From: kangax <kangax@xxxxxxxxx>
- Date: Wed, 23 Jul 2008 18:46:05 -0700 (PDT)
On Jul 23, 8:44 pm, "Richard Cornford" <Rich...@xxxxxxxxxxxxxxxxxxx>
wrote:
kangax wrote:
On Jul 21, 5:37 pm, Richard Cornford wrote:
[snip]
And finally, using the - concat - method to append an array created
from
the arguments object is very convoluted and relatively inefficient
when
the arguments object can be used as the second argument to the -
apply -
method and the - apply - method could be called on - push -, which
will
take any number of arguments and append them to an array. That is:-
__method.apply(object, args.concat($A(arguments))); - can be replaced
with - __method.apply(obj, args.push.apply(args, arguments)); - and
should result in superior performance.
I didn't know about Array.prototype.push being faster than
Array.prototype.concat in this case. Thanks for the tip.
Faster, but not usefully so.
However, it seems that the fastest method of turning an arguments object
into an array is:-
((arguments.length == 1)?[arguments[0]]:Array.apply(this, arguments))
- where - this - is the global object in my tests, but should not be
altered by the process so could be any object. I did try null as first
argument, which is fine on everything but Firefox, where it makes the
process considerably slower than using an object reference.
Unfortunately when the Array constructor, called as a function (so not
with the - new - keyword), is only given one argument and that argument
turns out to be a numeric value that is a positive integer smaller than
2 to the power of 32 then you get different behaviour. So the expression
has to include that special handling for (arguments.length == 1). My
test still show that whole expression outperforming all of the
alternatives that I could think of.
The precise benefit depends on the number of arguments. With zero
arguments the different can be very small on some browsers (especially
firefox and IE). I did my comparisons against Prototype.js's - $A -
function , which is considered to be 100% in the following numbers. At
20 arguments Windows Safari 3 executes that expression in 48% of the
time, and at zero arguments 47%. Mac Safari 2 was better, ranging from
16% with 20 arguments down to 34% with zero.
Opera 9.2 showed the next greatest performance change. 23% at 20
arguments and 57% at zero.
IE 7 came next with 62% at 20 arguments and 81% at zero.
IE 6: 65% to 89%.
Firefox 2.0.4 was the worst I have tried to date. At 20 arguments it
only manages 79% and was down to 85% by zero arguments, but the actual
execution time for the expression (and all of the alternatives) was the
longest of the group tested on the same hardware (by at least a factor
of 2) so the actual gain in time saved was still greater than for some
of the better performing JS engines.
Array.prototype.slice.call(arguments, X); - has still got to be the
fastest method if not all of the arguments are wanted, and (strangely) -
Array.prototype.splice.call(arguments, 0, arguments.length); - is
another alternative, but there, with Windows Safari 3, the benefit
dropped off with more arguments and at 8 arguments it was worse than -
$A -.
These were tests on a mixture of Pentium 4, Core 2 Duo and Core 2 Quad
processors and Windows and Mac OSs so the results may not yet be
sufficiently reprehensive for the comparisons to hold in general. I will
probably post the test code for these tomorrow (or soonish) in case
anyone wants to see if other hardware permutations contradict those
results (or try it with other browsers/OSs).
Richard.
Thanks for an exhaustive comparison.
Unfortunately, prototype.js's $A is a general-purpose function. That's
one of the reasons why it's slower than other alternatives. Besides
converting arguments object into an array, it's often used to convert
array-like objects (namely NodeList's) into actual arrays (by
exploiting length property that NodeList's expose).
$A is also used for delegating behavior to a passed object's toArray
method if an object has one. Delegating allows to decouple concerns,
as we know, so this pattern allows other data structures to define
"toArray" containing its own logic.
As an example, String.prototype.toArray is defined as:
....
function() {
return this.split('');
}
....
It would probably be wiser to use a separate function when converting
arguments to an array, rather than relying on a "heavier" $A. We might
consider this in later revisions.
Best,
--
kangax
.
- Follow-Ups:
- Re: addEvent - The late entry :)
- From: Richard Cornford
- Re: addEvent - The late entry :)
- References:
- addEvent - The late entry :)
- From: Aaron Gray
- Re: addEvent - The late entry :)
- From: Richard Cornford
- Re: addEvent - The late entry :)
- From: Peter Michaux
- Re: addEvent - The late entry :)
- From: Richard Cornford
- Re: addEvent - The late entry :)
- From: Peter Michaux
- Re: addEvent - The late entry :)
- From: jdalton
- Re: addEvent - The late entry :)
- From: Richard Cornford
- Re: addEvent - The late entry :)
- From: kangax
- Re: addEvent - The late entry :)
- From: Richard Cornford
- addEvent - The late entry :)
- Prev by Date: Re: addEvent - The late entry :)
- Next by Date: HTML Javascript as GUI for command line applications
- Previous by thread: Re: addEvent - The late entry :)
- Next by thread: Re: addEvent - The late entry :)
- Index(es):
Relevant Pages
|
Loading