RobG wrote:
Richard Cornford wrote: RobG wrote:
50***@web.de wrote:
<snip>
if (object.tagName.toUpperCase() == 'BODY'){
A more efficient test here is:
if ( /body/i.test(object.tagName) ){
<snip>
Is it a more efficient test? ...
<snip> I'm on lunch, so let's compare:
A. /body/i.test(object.tagName)
to
B. object.tagName.toUpperCase() == 'BODY'
Yes, that is the idea; test the proposition.
<snip> Just for fun, I put in a case C that uses a compiled
RegExp - the full script is below.
Worth observing the results (particularly in IE) but not part of the
original proposition.
Results vary by browser - Firefox, Netscape
& Mozilla were virtually identical,
As you would expect given that they all use the same JS engine.
so I've just reported Firefox:
A B C
Firefox 360 770 360
IE 950 310 360
Opera 530 820 530
Make what you will of that! For Geko-based browsers and Opera,
the RegExp method is about twice as fast always: for IE, the
string method is nearly 3 times faster unless a compiled RegExp
is used (this points to the others as compiling and caching the
RegExp regardless, but that is pure conjecture).
<snip> So given the above, I stand by my statement regarding
efficiency. Over to you.
My figures don't agree with yours. Taking string comparison as 100% I
get the following (fairly consistently):-
IE 6 Mozilla 1.6 Opera 7.54
(/body/i.test(S)) 328.9% 195.4% 54.2%
("BODY".toUpperCase() == S) 100% 100% 100%
Opera's regular expressions looks fast, or its string manipulation is
appalling, but IE and Mozilla come down in favour of string comparison.
<snip> while ( /BODY/i.test(t) && i-- ){}
I thought we were comparing - /body/i - not - /BODY/i -.
<snip> while ( t.toUpperCase() == 'BODY' && i-- ){}
<snip> <input ... onclick="doTest('BODY')"><br>
Good choice of string for the test ;) String comparisons that match
being the worst-case as the entire string needs to be processed in order
to determine that there is a match, while most non-matching strings will
be reveals by the first character comparison.
Some additional points worth mentioning are that - /body/i - will
produced a false positive if it encounters "TBODY", so the regular
expression - /^body$/i - would be preferable.
Most of the processing in - "BODY".toUpperCase() == S - is in the
implied creation of a String object for the method call, and the
subsequent method call. A comparison of - "BODY" == S - with (case
sensitive) - /^BODY$/.test(S) - demonstrates the extent to which this is
significant:-
IE 6 Mozilla 1.6 Opera 7.54
(/^BODY$/.test(S)) 3002.9% 24257.4% 1176.4%
("BODY" == S) 100% 100% 100%
- But because in HTML DOMs (in reality and by specification) the -
tagName - property is uppercase the overhead in trying to be case
insensitive is futile.
And finally, the most efficient formulation will be:-
if(object == document.body){ ...
My test page, for comparison and verification:-
<html>
<head>
<title></title>
<script type="text/javascript">
var frm = null;
var fncts = ['emptyL','regularExpression','stringComparison'];
var running = false;
function setButtons(bl){
frm['loopLimit'].disabled = bl;
frm["string"].disabled = bl
var sw = frm['bt'];
if(typeof sw.length == 'undefined'){
sw = [sw];
}
for(var c = 0;c < sw.length;c++){
sw[c].disabled = bl;
}
}
function doTests(){
if(!running){
frm = document.forms['f'].elements;
setButtons(true);
frm["Dur0"].value = '';frm["Avr0"].value = '';
for(var c = 1;c < fncts.length;c++){
frm["Dur"+c].value = '';
frm["Avr"+c].value = '';
frm["CAvr"+c].value = '';
frm["PAvr"+c].value = '';
frm["Res"+c].value = '';
}
running = true;
act(0);
}
}
function act(p){
/* setTimeout is used to minimise the occurrences
of 'a script on this page is running slow' dialogs. */
if(p >= fncts.length){
setTimeout('report()',100);
}else{
setTimeout((fncts[p]+'('+p+');'),200);
}
}
function report(){
var lim = +frm['loopLimit'].value;
var emDur = +frm["Dur0"].value
var unaC = (frm["Dur"+(fncts.length-1)].value - emDur) / lim;
frm["CAvr"+(fncts.length-1)].value = unaC;
frm["PAvr"+(fncts.length-1)].value = '100';
for(var c = 1;c < (fncts.length-1);c++){
var evaC = (frm["Dur"+c].value - emDur) / lim;
frm["CAvr"+c].value = evaC;
frm["PAvr"+c].value = ((evaC/unaC)*100);
}
setButtons(false);
running = false;
}
function emptyL(p){
var lim = +frm['loopLimit'].value;
var N, S = frm["string"].value;
var totTime,stTime = new Date().getTime();
for(var c = 0;c < lim;c++){
N = true;
}
totTime = (new Date().getTime() - stTime)
frm["Dur0"].value = totTime;
frm["Avr0"].value = (totTime/lim);
act(p+1);
}
function stringComparison(p){
var lim = +frm['loopLimit'].value;
var N, S = frm["string"].value;
var totTime,stTime = new Date().getTime();
for(var c = 0;c < lim;c++){
N = ("BODY".toUpperCase() == S)
}
totTime = (new Date().getTime() - stTime)
frm["Dur"+p].value = totTime;
frm["Avr"+p].value = (totTime/lim);
frm["Res"+p].value = N;
act(p+1);
}
function regularExpression(p){
var lim = +frm['loopLimit'].value;
var N, S = frm["string"].value;
var totTime,stTime = new Date().getTime();
for(var c = 0;c < lim;c++){
N = (/body/i.test(S));
}
totTime = (new Date().getTime() - stTime)
frm["Dur"+p].value = totTime;
frm["Avr"+p].value = (totTime/lim);
frm["Res"+p].value = N;
act(p+1);
}
</script>
</head>
<body>
<p>
<form name="f" action="#">
Loop Length = <input type="text" value="1300000"
name="loopLimit"> Some browsers will put up an "A script on
this page is making the browser run slowly" dialog. If this
happens the results for the test will be invalid and a shorter loop
will be needed. However, JavaScript Date objects do not tend to be
accurate to less than 10 milliseconds so duration results that are
not different by at least 20 milliseconds (and preferably 100+) are
not necessarily meaningful and a longer loop may be needed to acquire
useful results.<br><br>
Test Value = <input type="text" value="INPUT" name="string"> <br>
<input type="button" value="Test" name="bt" onclick="doTests();">
Repeat tests to reduce/expose the influence of background tasks.
<br><br>
Empty Loop Duration (milliseconds) = <input type="text" value="X"
name="Dur0"><br>
Empty Loop Average (milliseconds) = <input type="text" value="X"
name="Avr0" size="22"><br><br>
<code>(/body/i.test(S))</code> Duration (milliseconds) =
<input type="text" value="X" name="Dur1"><br>
<code>(/body/i.test(S))</code> Average (milliseconds) =
<input type="text" value="X" name="Avr1" size="22"><br>
(result = <input type="text" value="X" name="Res1" size="22">)<br><br>
<code>("BODY".toUpperCase() == S)</code> Duration (milliseconds) =
<input type="text" value="X" name="Dur2"><br>
<code>("BODY".toUpperCase() == S)</code> Average (milliseconds) =
<input type="text" value="X" name="Avr2" size="22"><br>
(result = <input type="text" value="X" name="Res2" size="22">)<br><br>
<br>
<input type="button" value="Test" name="bt" onclick="doTests();">
Repeat tests to reduce/expose the influence of background tasks.
<br><br>
Results: (duration of test - duration of empty loop) / loop length<br>
<code>(/body/i.test(S))</code> Average (milliseconds) =
<input type="text" value="X" name="CAvr1" size="22"><br>
<code>("BODY".toUpperCase() == S)</code> Average (milliseconds) =
<input type="text" value="X" name="CAvr2" size="22"><br>
<br>
Differences (<code>("BODY".toUpperCase() == S)</code> = 100%)<br>
<code>(/body/i.test(S))</code>
<input type="text" value="X" name="PAvr1" size="22">%<br>
<code>("BODY".toUpperCase() == S)</code>
<input type="text" value="X" name="PAvr2" size="22">%<br>
<br>
</form>
</p>
</body>
</html>
Richard.