• Shortcuts : 'n' next unread feed - 'p' previous unread feed • Styles : 1 2

» Publishers, Monetize your RSS feeds with FeedShow:  More infos  (Show/Hide Ads)


Date: Friday, 29 Jan 2010 21:25

Well folks, today is my last day at Sun. It's been challenging, aggravating, educational, terrifying, boring, exciting, and overall fun. I've worked with some absolutely amazing people and made several friends along the way. I've stared into the eyes of the Hydra—a multi-corporate, multi-national, multi-language, multi-architecture website—and kept my sanity. (At least that's what the voices in my head keep telling me.) So far as I'm concerned, that's an accomplishment.

So farewell, people of Sun. Oracle, I never knew ye, but you've got a tiger by the tail, and I'll be curious to see what research and innovations the new combined company brings to bear. What a tech portfolio that will be!


Contact info

Linkedin: http://www.linkedin.com/in/gregreimer
Facebook: http://www.facebook.com/people/Greg-Reimer/603647710
Non-Sun Blog: http://gregreimer.wordpress.com/
Email: gregreimer ~at~ gmail ~dot~ com


Author: "greimer" Tags: "Sun"
Send by mail Print  Save  Delicious 
Date: Wednesday, 11 Mar 2009 21:02
I'm now rockin' the ultimate multi-browser testing environment with VirtualBox. No longer must I endure the rigmarole of booting up separate physical Windows machines in order to test different versions of IE, or fooling with unwieldy hacks to get multiple versions of IE running on the same instance of Windows. I simply unpause the appropriate virtual OS instance and go to town. I'm sure that my list of virtual OSes will grow in the future.
Author: "greimer" Tags: "Tech, browsers, testing, virtualbox"
Send by mail Print  Save  Delicious 
Date: Saturday, 06 Dec 2008 09:07

Anybody who's ever implemented or used event delegation knows first-hand the bitter pain of IE's lack of bubbling on those events. Bitter, bitter pain.

Well, the reglib trunk has just received experimental beta support for those events. The technique is of course to co-opt other events that *do* bubble, and that are almost certain to be executed prior to the non-bubbling event. Within the co-opted, bubbling event, the non-bubbling event handler is added.

The fly in the ointment is the "almost" in the above phrase, "almost certain." At the very least, these events can be triggered programatically, without any prior events firing. But I thought what the heck, might as well build it and see how useful it is in the real world.

Of course many browsers do support bubbling on these events, so they get reglib's natural event delegation. Although I'll probably need a more sophisticated test, if(document.all&&!window.opera) seems a bit crude, but I wanted to get this into the trunk and in front of people. I'm sure I'll wake up in a cold sweat tonight and realize I need to recode the whole darn thing.

Here are the new methods:

reg.submit(selector,function);
reg.reset(selector,function);
reg.select(selector,function);
reg.change(selector,function);

More info: all reglib posts, reglib feed, download reglib


Update: So far the results are pretty promising, better than I had hoped even. Early iterations of the code were a bit unweildy and bug-prone, then I had an epiphany and about 90% of the code and complexity evaporated, leaving a solution that seems pretty tight, altogether.

Basically, it sets up reglib's existing delegation on the fly, directly on the element that receives the non-bubbling event. E.g. for the change event, it more or less does reg.focus('select',setDelegationOnThis) to ensure the delegation gets set up prior to a change event. Of course this is only done on IE. Everything bubbles normally for modern browsers. They are quite boring, those modern browsers.

Author: "greimer" Tags: "Tech, delegation, events, reglib"
Send by mail Print  Save  Delicious 
Date: Thursday, 04 Dec 2008 20:45

Looks like Opera 10 will support the selector API. Now if only there were an Element.is(selector) DOM method for us event delegation geeks...

Author: "greimer" Tags: "Tech, javascript, selectors"
Send by mail Print  Save  Delicious 
Date: Tuesday, 02 Dec 2008 08:49

UPDATE: I've removed reg.pause() and reg.resume() from the trunk. Sean Hogan makes a good point in the comments below. Plus, now that reglib is doing delegation on form events, things get complicated maintaining the pause/resume system alongside the branch of code that simulates bubbling for form events in IE. One can still easily disable an event by using a selector like this: "body.on a@href" and then adding/remove 'on' from the body classname as necessary.


reglib has reached 1.0.6. Updates include:

reg.pause() and reg.resume() follow a similar pattern to reg.removeEvent():

// handle hover on all links
var hoverLinks = reg.hover('a@href',function(e){
    // handle mouseenter
},function(e){
    // handle mouseleave
});

// stop handling hover on links
reg.pause(hoverLinks);

// resume handling hover on links
reg.resume(hoverLinks);

More info: all reglib posts, reglib feed, download reglib

Author: "greimer" Tags: "Tech, delegation, events, javascript, re..."
Send by mail Print  Save  Delicious 
Date: Tuesday, 25 Nov 2008 22:53

I decided that mouseover/out is never the behavior I want, whereas mouseenter/leave is always the behavior I want. Practically always. So I've changed over reglib's reg.hover() to behave like mouseenter/leave.

For Example

Say you have this HTML structure:

<div>
  <p>
    <span>
      <a>
        mouse over me
      </a>
    </span>
  </p>
</div>

Which I tend to visualize as a ziggurat-like object:

a nested hierarchy of elements

...and then you have this event handler:

// note, the think() function is purely fanciful

reg.hover('div',function(e){
    think(e.type, e.target);
},function(e){
    think(e.type, e.target);
});

Up until now, reglib behaved like a typical mouseover/out event handler, which in a nested element/bubbling situation isn't what you really want. The mouse movement is represented by the little arrow:

mouse enters div, triggers mouseover mouse enters nested p, triggers mouseout, mouseover mouse leaves nested p, triggers mouseout, mouseover mouse leaves div, triggers mouseout

So anyways, as I said, this is a bit wonky and unnecessary. Therefore the next version of reglib will (if all goes to plan) behave thusly:

mouse enters div, triggers mouseover mouse enters nested p, nothing happens mouse leaves nested p, nothing happens mouse leaves div, triggers mouseout

The title of this post is a bit misleading. The mouseenter/leave events are never used. It's all still accomplished via mouseover/out, but there's enough information available in the handling element, event.target and event.relatedTarget elements--and their positions relative to each other--to know whether to execute the handler. Since the actual mouseenter/leave events don't bubble, and in any case are IE-only, reglib wants nothing to do with them. This code is checked in to the trunk, and with a little more testing will be released as reglib version 1.0.5.

One thing also, I'd be curious to know if anybody knows of a reason this would be *undesirable* behavior.


For more info: see all reglib posts, grab the reglib feed, reglib on google code

Author: "greimer" Tags: "Tech, events, javascript, reglib"
Send by mail Print  Save  Delicious 
Date: Monday, 24 Nov 2008 06:14

reglib is up to 1.0.4. Some bugs are fixed and some features are added since the 1.0 release:

Here's an example of removeEvent():

var el = reg.gebi('myid');

// mem is just an id
// similar to that returned by setTimeout()
var mem = reg.addEvent(el, 'click', function(e){
    // do stuff here
});

// later on, remove the event
// similar to clearTimeout()
reg.removeEvent(mem);

Personally, I don't use these direct-attachment functions very much because I prefer to use reglib's built-in event delegation, but it's nice to have them around.

More info: all reglib posts, reglib feed, download reglib

Author: "greimer" Tags: "Tech, events, reglib"
Send by mail Print  Save  Delicious 
Date: Saturday, 15 Nov 2008 20:46

Read the reglib tag trail for more about reglib, or subscribe to the feed of all things tagged reglib.

Let me first of all stress that I'm not trying to bust on JQuery here. JQuery does something that needs to be done, and it does it just about as well as can be done given the tool-set browsers have collectively placed at our disposal.

With that said, I'm going to go ahead and pimp the reglib way of doing things, by which I mean declarative, over the load-traverse-modify methodology, which JQuery makes so easy.

The demo page linked below has two identical interactive widgets; one wired up using JQuery, and the other wired up using reglib.

» Demo Page «

The page is rigged like a science experiment, with a control followed by several tests in which you observe differences in behavior between the two widgets in response to various stimuli. The goal is to demonstrate reglib's resilience under duress (as it were). Enjoy.

Author: "greimer" Tags: "Tech, delegation, events, javascript, li..."
Send by mail Print  Save  Delicious 
Date: Monday, 10 Nov 2008 21:30

The reglib is now published to Google Code and available under the MIT license.

Project Home: http://code.google.com/p/reglib/
Download: http://code.google.com/p/reglib/downloads/list

The backstory - Almost a year ago1 I made all kinds of big talk about releasing a JavaScript lib I was developing for sun.com. This library obviates (some of) the need for what I call the load-traverse-modify methodology of unobtrusive JavaScript:

  • Load: make it your business to know when the DOM has loaded.
  • Traverse: use a query to scan said DOM, returning a list of elements.
  • Modify: attach event handlers to, and otherwise manipulate, those elements.

Although LTM is quite common in JavaScript development, I believe it's an antipattern. The reglib tries to get closer to the CSS way of doing things: declare what kinds of elements get what behavior, and have that declaration take immediate effect at a global level, regardless of subsequent mutations to the DOM.

// JAVASCRIPT CODE:
reg.click("a.popup", function(e){
    window.open(this.href);
    return false;
});

/*
ENGLISH TRANSLATION:
I declare, forthwith, that all clicks on <a> elements with
class "popup" shall be handled thusly...
*/

So there you have it. Feel free to check it out (just check it out or actually check it out), read the documentation wiki, download, leave comments, etc. The lib also has a bunch of convenience functions for DOM manipulation, plus it has tools for doing LTM stuff because let's face it, sometimes there's no other way.

(Previous posts on this topic can be found here and here.)


1 It took so long because, in a nutshell: 1) Sun has an open source review process, you can't just release code willy-nilly, 2) During the process, I failed to be a squeaky wheel, and in fact the lawyers waited on my responses as much as I waited on their responses. However development over that interval has been constantly active, and reglib is being used on sun.com.

Author: "greimer" Tags: "Tech, delegation, events, javascript, li..."
Send by mail Print  Save  Delicious 
Date: Friday, 25 Jul 2008 02:00

I built a loop benchmarking test suite for different ways of coding loops in JavaScript. There are a few of these out there already, but I didn't find any that acknowledged the difference between native arrays and HTML collections. Since the underlying implementations are different (HTML collections for example lack the pop() and slice() methods, etc), benchmarks that don't test against both are probably missing important information.

My suspicions were confirmed. Accessing the length property is more expensive on HTML collections than on arrays, depending on the browser. In those cases, caching it made a huge difference. However, HTML collections are live, so a cached value may fail if the underlying DOM is modified during looping. On the other hand, HTML collections will never be sparse, so the best way to loop an HTML collection might just be to ignore the length property altogether and combine the test with the item lookup, since you have to do that anyway:

// looping a dom html collection
for (var i=0, node; node = hColl[i++];) {
    // do something with node
}

Another interesting result is that with HTML collections, hColl.item(i) is 2-6x slower than hColl[i], except in Safari where it's about the same. I wonder what the extra overhead is?

I've posted the results of all my benchmarks here, however my IE7 is really IE8 in IE7 emulation mode, so I mistrust these results as representing IE7's original JavaScript/DOM engine. If anybody wants to run the benchmarks in true IE7 and post the results, I'll update this post accordingly. Thanks to Kyle Simpson for the benchmarks. Also, I'm sure there are ways of looping that escaped my imagination, so if you know of any, post it in the comments and I'll add them to the test page.


[edit] To prevent overly-helpful "this script is taking too long" warnings from skewing the results, in IE you might have to edit your MaxScriptStatements registry setting. In Gecko it's dom.max_script_run_time under about:config.


table.data{font-size:11px;} caption{text-align:left;font-weight:bold;padding-left:30px;font-size:12px;margin-top:20px;} table.data td.code{white-space:pre;} td.bench{font-weight:bold;}

Firefox 3.0.1 / OS X 10.5 / 2x3GHZ

Native Array (length=1000, looped 100 times)
Basic for loop.for (var i=0; i<arr.length; i++) {} 4ms
For loop, but caching the length.for (var i=0, len=arr.length; i<len; i++) {} 3ms
While loop that imitates a for loop.var i = 0;
while (i<arr.length) {
i++;
}
4ms
While loop that imitates a for loop, caching the length.var i=0, len=arr.length;
while (i<len) {
i++;
}
3ms
While loop in reverse, simplifying the test condition.var i = arr.length; while (i--) {} 2ms
While looping by popping values (this fails on sparse arrays).var x;
while (x = arr.pop()) {}
9ms
for ... in loopfor (var i in arr) {} 28ms
for ... in loop, with integer testvar isInt = /(^[0-9]$)|(^[1-9][0-9]+$)/;
for (var i in arr) {
if(!isInt.test(i)){continue;}
}
93ms
For loop, testing on existence rather than length (this fails on sparse arrays).for (var i=0; arr[i]; i++) {} 3ms
For loop, testing on existence rather than length, plus array lookup.for (var i=0; arr[i]; i++) {
var x = arr[i];
}
6ms
For loop, testing on existence rather than length, array lookup is combined with test.for (var i=0, x; x = arr[i++];) {} 4ms
For reference.for (var i=0, len=arr.length; i<len; i++) {
var x = arr[i];
}
5ms
Array.forEach() native implementation.arr.forEach(function(x){}); 51ms
For reference against forEach().var f=function(x){};
for (var i=0, len=arr.length; i<len; i++) {
f(arr[i]);
}
51ms
Sparse Native Array (length=12200, sporadically populated with 1000 items, looped 100 times)
Basic for loop.for (var i=0; i<sarr.length; i++) {} 81ms
For loop, but caching the length.for (var i=0, len=sarr.length; i<len; i++) {} 35ms
While loop that imitates a for loop.var i = 0; while (i<sarr.length) {
i++;
}
79ms
While loop that imitates a for loop, caching the length.var i = 0, len = sarr.length; while (i<len) {
i++;
}
32ms
While loop in reverse, simplifying the test condition.var i=sarr.length; while (i--) {} 22ms
for ... in loopfor (var i in sarr) {} 30ms
for ... in loop, with integer testvar isInt = /(^[0-9]$)|(^[1-9][0-9]+$)/;
for (var i in sarr) {
if(!isInt.test(i)){continue;}
}
96ms
Array.forEach() native implementation.sarr.forEach(function(x){}); 178ms
For reference against forEach().var f=function(x){};
for (var i=0, len=sarr.length; i<len; i++) {
f(sarr[i]);
}
769ms
HTML Collection (length=1000, looped 100 times)
Basic for loop.for (var i=0; i<hColl.length; i++) {} 119ms
For loop, but caching the length.for (var i=0, len=hColl.length; i<len; i++) {} 3ms
While loop that imitates a for loop.var i = 0; while (i<hColl.length) {
i++;
}
119ms
While loop that imitates a for loop, caching the length.var i=0, len=hColl.length; while (i<len) {
i++;
}
3ms
While loop in reverse, simplifying the test condition.var i=hColl.length; while (i--) {} 2ms
for ... in loopfor (var i in hColl) {} 97ms
for ... in loop, with integer testvar isInt = /(^[0-9]$)|(^[1-9][0-9]+$)/;
for (var i in hColl) {
if(!isInt.test(i)){continue;}
}
163ms
For loop, testing on existence rather than length (this fails on sparse arrays).for (var i=0; hColl[i]; i++) {} 114ms
For loop, testing on existence rather than length, plus array lookup.for (var i=0; hColl[i]; i++) {
var x = hColl[i];
}
189ms
For loop, testing on existence rather than length, array lookup is combined with test.for (var i=0, x; x = hColl[i++];) {} 95ms
For loop, testing on existence rather than length, array lookup is combined with test, item() instead of array brackets.for (var i=0, x; x = hColl.item(i++);) {} 235ms
For reference.for (var i=0, len=hColl.length; i<len; i++) {
var x = hColl[i];
}
98ms

Firefox 2.0 / WinXP / 1.95GHZ

Native Array (length=1000, looped 100 times)
Basic for loop.for (var i=0; i<arr.length; i++) {} 47ms
For loop, but caching the length.for (var i=0, len=arr.length; i<len; i++) {}16ms
While loop that imitates a for loop.var i = 0;
while (i<arr.length) {
i++;
}
31ms
While loop that imitates a for loop, caching the length.var i=0, len=arr.length;
while (i<len) {
i++;
}
16ms
While loop in reverse, simplifying the test condition.var i = arr.length; while (i--) {}15ms
While looping by popping values (this fails on sparse arrays).var x;
while (x = arr.pop()) {}
281ms
for ... in loopfor (var i in arr) {}375ms
for ... in loop, with integer testvar isInt = /(^[0-9]$)|(^[1-9][0-9]+$)/;
for (var i in arr) {
if(!isInt.test(i)){continue;}
}
906ms
For loop, testing on existence rather than length (this fails on sparse arrays).for (var i=0; arr[i]; i++) {} 32ms
For loop, testing on existence rather than length, plus array lookup.for (var i=0; arr[i]; i++) {
var x = arr[i];
}
62ms
For loop, testing on existence rather than length, array lookup is combined with test.for (var i=0, x; x = arr[i++];) {} 31ms
For reference.for (var i=0, len=arr.length; i<len; i++) {
var x = arr[i];
}
47ms
Array.forEach() native implementation.arr.forEach(function(x){}); 391ms
For reference against forEach().var f=function(x){};
for (var i=0, len=arr.length; i<len; i++) {
f(arr[i]);
}
422ms
Sparse Native Array (length=12634, sporadically populated with 1000 items, looped 100 times)
Basic for loop.for (var i=0; i<sarr.length; i++) {} 453ms
For loop, but caching the length.for (var i=0, len=sarr.length; i<len; i++) {}203ms
While loop that imitates a for loop.var i = 0; while (i<sarr.length) {
i++;
}
469ms
While loop that imitates a for loop, caching the length.var i = 0, len = sarr.length; while (i<len) {
i++;
}
218ms
While loop in reverse, simplifying the test condition.var i=sarr.length; while (i--) {}172ms
for ... in loopfor (var i in sarr) {}328ms
for ... in loop, with integer testvar isInt = /(^[0-9]$)|(^[1-9][0-9]+$)/;
for (var i in sarr) {
if(!isInt.test(i)){continue;}
}
875ms
Array.forEach() native implementation.sarr.forEach(function(x){}); 750ms
For reference against forEach().var f=function(x){};
for (var i=0, len=sarr.length; i<len; i++) {
f(sarr[i]);
}
6000ms
HTML Collection (length=1000, looped 100 times)
Basic for loop.for (var i=0; i<hColl.length; i++) {} 891ms
For loop, but caching the length.for (var i=0, len=hColl.length; i<len; i++) {}16ms
While loop that imitates a for loop.var i = 0; while (i<hColl.length) {
i++;
}
906ms
While loop that imitates a for loop, caching the length.var i=0, len=hColl.length; while (i<len) {
i++;
}
16ms
While loop in reverse, simplifying the test condition.var i=hColl.length; while (i--) {}15ms
for ... in loopfor (var i in hColl) {} 625ms
for ... in loop, with integer testvar isInt = /(^[0-9]$)|(^[1-9][0-9]+$)/;
for (var i in hColl) {
if(!isInt.test(i)){continue;}
}
1188ms
For loop, testing on existence rather than length (this fails on sparse arrays).for (var i=0; hColl[i]; i++) {} 453ms
For loop, testing on existence rather than length, plus array lookup.for (var i=0; hColl[i]; i++) {
var x = hColl[i];
}
797ms
For loop, testing on existence rather than length, array lookup is combined with test.for (var i=0, x; x = hColl[i++];) {} 437ms
For loop, testing on existence rather than length, array lookup is combined with test, item() instead of array brackets.for (var i=0, x; x = hColl.item(i++);) {} 1438ms
For reference.for (var i=0, len=hColl.length; i<len; i++) {
var x = hColl[i];
}
437ms

Camino 1.6.1 / OS X 10.5 / 2x3GHZ

Native Array (length=1000, looped 100 times)
Basic for loop.for (var i=0; i<arr.length; i++) {} 8ms
For loop, but caching the length.for (var i=0, len=arr.length; i<len; i++) {} 4ms
While loop that imitates a for loop.var i = 0;
while (i<arr.length) {
i++;
}
9ms
While loop that imitates a for loop, caching the length.var i=0, len=arr.length;
while (i<len) {
i++;
}
4ms
While loop in reverse, simplifying the test condition.var i = arr.length; while (i--) {} 2ms
While looping by popping values (this fails on sparse arrays).var x;
while (x = arr.pop()) {}
85ms
for ... in loopfor (var i in arr) {} 44ms
for ... in loop, with integer testvar isInt = /(^[0-9]$)|(^[1-9][0-9]+$)/;
for (var i in arr) {
if(!isInt.test(i)){continue;}
}
163ms
For loop, testing on existence rather than length (this fails on sparse arrays).for (var i=0; arr[i]; i++) {} 10ms
For loop, testing on existence rather than length, plus array lookup.for (var i=0; arr[i]; i++) {
var x = arr[i];
}
14ms
For loop, testing on existence rather than length, array lookup is combined with test.for (var i=0, x; x = arr[i++];) {} 10ms
For reference.for (var i=0, len=arr.length; i<len; i++) {
var x = arr[i];
}
11ms
Array.forEach() native implementation.arr.forEach(function(x){}); 111ms
For reference against forEach().var f=function(x){};
for (var i=0, len=arr.length; i<len; i++) {
f(arr[i]);
}
105ms
Sparse Native Array (length=11999, sporadically populated with 1000 items, looped 100 times)
Basic for loop.for (var i=0; i<sarr.length; i++) {} 103ms
For loop, but caching the length.for (var i=0, len=sarr.length; i<len; i++) {} 45ms
While loop that imitates a for loop.var i = 0; while (i<sarr.length) {
i++;
}
99ms
While loop that imitates a for loop, caching the length.var i = 0, len = sarr.length; while (i<len) {
i++;
}
42ms
While loop in reverse, simplifying the test condition.var i=sarr.length; while (i--) {} 33ms
for ... in loopfor (var i in sarr) {} 52ms
for ... in loop, with integer testvar isInt = /(^[0-9]$)|(^[1-9][0-9]+$)/;
for (var i in sarr) {
if(!isInt.test(i)){continue;}
}
151ms
Array.forEach() native implementation.sarr.forEach(function(x){}); 217ms
For reference against forEach().var f=function(x){};
for (var i=0, len=sarr.length; i<len; i++) {
f(sarr[i]);
}
1338ms
HTML Collection (length=1000, looped 100 times)
Basic for loop.for (var i=0; i<hColl.length; i++) {} 270ms
For loop, but caching the length.for (var i=0, len=hColl.length; i<len; i++) {} 4ms
While loop that imitates a for loop.var i = 0; while (i<hColl.length) {
i++;
}
270ms
While loop that imitates a for loop, caching the length.var i=0, len=hColl.length; while (i<len) {
i++;
}
4ms
While loop in reverse, simplifying the test condition.var i=hColl.length; while (i--) {} 3ms
for ... in loopfor (var i in hColl) {} 106ms
for ... in loop, with integer testvar isInt = /(^[0-9]$)|(^[1-9][0-9]+$)/;
for (var i in hColl) {
if(!isInt.test(i)){continue;}
}
224ms
For loop, testing on existence rather than length (this fails on sparse arrays).for (var i=0; hColl[i]; i++) {} 119ms
For loop, testing on existence rather than length, plus array lookup.for (var i=0; hColl[i]; i++) {
var x = hColl[i];
}
220ms
For loop, testing on existence rather than length, array lookup is combined with test.for (var i=0, x; x = hColl[i++];) {} 115ms
For loop, testing on existence rather than length, array lookup is combined with test, item() instead of array brackets.for (var i=0, x; x = hColl.item(i++);) {} 397ms
For reference.for (var i=0, len=hColl.length; i<len; i++) {
var x = hColl[i];
}
114ms

Mozilla 1.7.12 / OS X 10.5 / 2x3GHZ

Native Array (length=1000, looped 100 times)
Basic for loop.for (var i=0; i<arr.length; i++) {} 40ms
For loop, but caching the length.for (var i=0, len=arr.length; i<len; i++) {}14ms
While loop that imitates a for loop.var i = 0;
while (i<arr.length) {
i++;
}
22ms
While loop that imitates a for loop, caching the length.var i=0, len=arr.length;
while (i<len) {
i++;
}
13ms
While loop in reverse, simplifying the test condition.var i = arr.length; while (i--) {} 9ms
While looping by popping values (this fails on sparse arrays).var x;
while (x = arr.pop()) {}
388ms
for ... in loopfor (var i in arr) {}263ms
for ... in loop, with integer testvar isInt = /(^[0-9]$)|(^[1-9][0-9]+$)/;
for (var i in arr) {
if(!isInt.test(i)){continue;}
}
1126ms
For loop, testing on existence rather than length (this fails on sparse arrays).for (var i=0; arr[i]; i++) {} 27ms
For loop, testing on existence rather than length, plus array lookup.for (var i=0; arr[i]; i++) {
var x = arr[i];
}
48ms
For loop, testing on existence rather than length, array lookup is combined with test.for (var i=0, x; x = arr[i++];) {} 26ms
For reference.for (var i=0, len=arr.length; i<len; i++) {
var x = arr[i];
}
32ms
Array.forEach() custom implementation.arr.forEach(function(x){}); 666ms
For reference against forEach().var f=function(x){};
for (var i=0, len=arr.length; i<len; i++) {
f(arr[i]);
}
148ms
Sparse Native Array (length=11605, sporadically populated with 1000 items, looped 100 times)
Basic for loop.for (var i=0; i<sarr.length; i++) {} 264ms
For loop, but caching the length.for (var i=0, len=sarr.length; i<len; i++) {}157ms
While loop that imitates a for loop.var i = 0; while (i<sarr.length) {
i++;
}
255ms
While loop that imitates a for loop, caching the length.var i = 0, len = sarr.length; while (i<len) {
i++;
}
180ms
While loop in reverse, simplifying the test condition.var i=sarr.length; while (i--) {}103ms
for ... in loopfor (var i in sarr) {}236ms
for ... in loop, with integer testvar isInt = /(^[0-9]$)|(^[1-9][0-9]+$)/;
for (var i in sarr) {
if(!isInt.test(i)){continue;}
}
1027ms
Array.forEach() custom implementation.sarr.forEach(function(x){}); 1076ms
For reference against forEach().var f=function(x){};
for (var i=0, len=sarr.length; i<len; i++) {
f(sarr[i]);
}
1881ms
HTML Collection (length=1000, looped 100 times)
Basic for loop.for (var i=0; i<hColl.length; i++) {}1888ms
For loop, but caching the length.for (var i=0, len=hColl.length; i<len; i++) {}18ms
While loop that imitates a for loop.var i = 0; while (i<hColl.length) {
i++;
}
1855ms
While loop that imitates a for loop, caching the length.var i=0, len=hColl.length; while (i<len) {
i++;
}
17ms
While loop in reverse, simplifying the test condition.var i=hColl.length; while (i--) {}24ms
for ... in loopfor (var i in hColl) {} 578ms
for ... in loop, with integer testvar isInt = /(^[0-9]$)|(^[1-9][0-9]+$)/;
for (var i in hColl) {
if(!isInt.test(i)){continue;}
}
1455ms
For loop, testing on existence rather than length (this fails on sparse arrays).for (var i=0; hColl[i]; i++) {}1182ms
For loop, testing on existence rather than length, plus array lookup.for (var i=0; hColl[i]; i++) {
var x = hColl[i];
}
2072ms
For loop, testing on existence rather than length, array lookup is combined with test.for (var i=0, x; x = hColl[i++];) {}1102ms
For loop, testing on existence rather than length, array lookup is combined with test, item() instead of array brackets.for (var i=0, x; x = hColl.item(i++);) {} 2542ms
For reference.for (var i=0, len=hColl.length; i<len; i++) {
var x = hColl[i];
}
1115ms

Safari 3.1.2 / OS X 10.5 / 2x3GHZ

Native Array (length=1000, looped 100 times)
Basic for loop.for (var i=0; i<arr.length; i++) {} 5ms
For loop, but caching the length.for (var i=0, len=arr.length; i<len; i++) {} 3ms
While loop that imitates a for loop.var i = 0;
while (i<arr.length) {
i++;
}
6ms
While loop that imitates a for loop, caching the length.var i=0, len=arr.length;
while (i<len) {
i++;
}
4ms
While loop in reverse, simplifying the test condition.var i = arr.length; while (i--) {} 2ms
While looping by popping values (this fails on sparse arrays).var x;
while (x = arr.pop()) {}
18ms
for ... in loopfor (var i in arr) {} 42ms
for ... in loop, with integer testvar isInt = /(^[0-9]$)|(^[1-9][0-9]+$)/;
for (var i in arr) {
if(!isInt.test(i)){continue;}
}
80ms
For loop, testing on existence rather than length (this fails on sparse arrays).for (var i=0; arr[i]; i++) {} 5ms
For loop, testing on existence rather than length, plus array lookup.for (var i=0; arr[i]; i++) {
var x = arr[i];
}
8ms
For loop, testing on existence rather than length, array lookup is combined with test.for (var i=0, x; x = arr[i++];) {} 5ms
For reference.for (var i=0, len=arr.length; i<len; i++) {
var x = arr[i];
}
7ms
Array.forEach() native implementation.arr.forEach(function(x){}); 11ms
For reference against forEach().var f=function(x){};
for (var i=0, len=arr.length; i<len; i++) {
f(arr[i]);
}
19ms
Sparse Native Array (length=10565, sporadically populated with 1000 items, looped 100 times)
Basic for loop.for (var i=0; i<sarr.length; i++) {} 54ms
For loop, but caching the length.for (var i=0, len=sarr.length; i<len; i++) {} 31ms
While loop that imitates a for loop.var i = 0; while (i<sarr.length) {
i++;
}
71ms
While loop that imitates a for loop, caching the length.var i = 0, len = sarr.length; while (i<len) {
i++;
}
45ms
While loop in reverse, simplifying the test condition.var i=sarr.length; while (i--) {} 19ms
for ... in loopfor (var i in sarr) {} 41ms
for ... in loop, with integer testvar isInt = /(^[0-9]$)|(^[1-9][0-9]+$)/;
for (var i in sarr) {
if(!isInt.test(i)){continue;}
}
77ms
Array.forEach() native implementation.sarr.forEach(function(x){}); 285ms
For reference against forEach().var f=function(x){};
for (var i=0, len=sarr.length; i<len; i++) {
f(sarr[i]);
}
482ms
HTML Collection (length=1000, looped 100 times)
Basic for loop.for (var i=0; i<hColl.length; i++) {} 8ms
For loop, but caching the length.for (var i=0, len=hColl.length; i<len; i++) {} 3ms
While loop that imitates a for loop.var i = 0; while (i<hColl.length) {
i++;
}
8ms
While loop that imitates a for loop, caching the length.var i=0, len=hColl.length; while (i<len) {
i++;
}
4ms
While loop in reverse, simplifying the test condition.var i=hColl.length; while (i--) {} 2ms
for ... in loopfor (var i in hColl) {} 47ms
for ... in loop, with integer testvar isInt = /(^[0-9]$)|(^[1-9][0-9]+$)/;
for (var i in hColl) {
if(!isInt.test(i)){continue;}
}
86ms
For loop, testing on existence rather than length (this fails on sparse arrays).for (var i=0; hColl[i]; i++) {} 58ms
For loop, testing on existence rather than length, plus array lookup.for (var i=0; hColl[i]; i++) {
var x = hColl[i];
}
107ms
For loop, testing on existence rather than length, array lookup is combined with test.for (var i=0, x; x = hColl[i++];) {} 59ms
For loop, testing on existence rather than length, array lookup is combined with test, item() instead of array brackets.for (var i=0, x; x = hColl.item(i++);) {} 53ms
For reference.for (var i=0, len=hColl.length; i<len; i++) {
var x = hColl[i];
}
60ms

Opera 9.51 / OS X 10.5 / 2x3GHZ

Native Array (length=1000, looped 100 times)
Basic for loop.for (var i=0; i<arr.length; i++) {} 7ms
For loop, but caching the length.for (var i=0, len=arr.length; i<len; i++) {} 7ms
While loop that imitates a for loop.var i = 0;
while (i<arr.length) {
i++;
}
7ms
While loop that imitates a for loop, caching the length.var i=0, len=arr.length;
while (i<len) {
i++;
}
7ms
While loop in reverse, simplifying the test condition.var i = arr.length; while (i--) {} 3ms
While looping by popping values (this fails on sparse arrays).var x;
while (x = arr.pop()) {}
28ms
for ... in loopfor (var i in arr) {} 58ms
for ... in loop, with integer testvar isInt = /(^[0-9]$)|(^[1-9][0-9]+$)/;
for (var i in arr) {
if(!isInt.test(i)){continue;}
}
299ms
For loop, testing on existence rather than length (this fails on sparse arrays).for (var i=0; arr[i]; i++) {} 9ms
For loop, testing on existence rather than length, plus array lookup.for (var i=0; arr[i]; i++) {
var x = arr[i];
}
18ms
For loop, testing on existence rather than length, array lookup is combined with test.for (var i=0, x; x = arr[i++];) {} 9ms
For reference.for (var i=0, len=arr.length; i<len; i++) {
var x = arr[i];
}
13ms
Array.forEach() native implementation.arr.forEach(function(x){}); 54ms
For reference against forEach().var f=function(x){};
for (var i=0, len=arr.length; i<len; i++) {
f(arr[i]);
}
27ms
Sparse Native Array (length=12171, sporadically populated with 1000 items, looped 100 times)
Basic for loop.for (var i=0; i<sarr.length; i++) {} 94ms
For loop, but caching the length.for (var i=0, len=sarr.length; i<len; i++) {} 76ms
While loop that imitates a for loop.var i = 0; while (i<sarr.length) {
i++;
}
92ms
While loop that imitates a for loop, caching the length.var i = 0, len = sarr.length; while (i<len) {
i++;
}
74ms
While loop in reverse, simplifying the test condition.var i=sarr.length; while (i--) {} 42ms
for ... in loopfor (var i in sarr) {} 63ms
for ... in loop, with integer testvar isInt = /(^[0-9]$)|(^[1-9][0-9]+$)/;
for (var i in sarr) {
if(!isInt.test(i)){continue;}
}
286ms
Array.forEach() native implementation.sarr.forEach(function(x){}); 230ms
For reference against forEach().var f=function(x){};
for (var i=0, len=sarr.length; i<len; i++) {
f(sarr[i]);
}
442ms
HTML Collection (length=1000, looped 100 times)
Basic for loop.for (var i=0; i<hColl.length; i++) {} 28ms
For loop, but caching the length.for (var i=0, len=hColl.length; i<len; i++) {} 5ms
While loop that imitates a for loop.var i = 0; while (i<hColl.length) {
i++;
}
28ms
While loop that imitates a for loop, caching the length.var i=0, len=hColl.length; while (i<len) {
i++;
}
6ms
While loop in reverse, simplifying the test condition.var i=hColl.length; while (i--) {} 4ms
for ... in loopfor (var i in hColl) {} 113ms
for ... in loop, with integer testvar isInt = /(^[0-9]$)|(^[1-9][0-9]+$)/;
for (var i in hColl) {
if(!isInt.test(i)){continue;}
}
380ms
For loop, testing on existence rather than length (this fails on sparse arrays).for (var i=0; hColl[i]; i++) {} 36ms
For loop, testing on existence rather than length, plus array lookup.for (var i=0; hColl[i]; i++) {
var x = hColl[i];
}
60ms
For loop, testing on existence rather than length, array lookup is combined with test.for (var i=0, x; x = hColl[i++];) {} 37ms
For loop, testing on existence rather than length, array lookup is combined with test, item() instead of array brackets.for (var i=0, x; x = hColl.item(i++);) {} 175ms
For reference.for (var i=0, len=hColl.length; i<len; i++) {
var x = hColl[i];
}
41ms

IE 7.0.5730.11 / WinXP SP2

Native Array (length=1000, looped 100 times)
Basic for loop.for (var i=0; i<arr.length; i++) {} 31ms
For loop, but caching the length.for (var i=0, len=arr.length; i<len; i++) {}15ms
While loop that imitates a for loop.var i = 0;
while (i<arr.length) {
i++;
}
32ms
While loop that imitates a for loop, caching the length.var i=0, len=arr.length;
while (i<len) {
i++;
}
15ms
While loop in reverse, simplifying the test condition.var i = arr.length; while (i--) {} 0ms
do ... while loop in reverse.var i = arr.length-1; do { } while (i--);16ms
for loop in reverse.for (var i=arr.length; i--;) { }0ms
While looping by popping values (this fails on sparse arrays).var x;
while (x = arr.pop()) {}
2907ms
for ... in loopfor (var i in arr) {}140ms
for ... in loop, with integer testvar isInt = /(^[0-9]$)|(^[1-9][0-9]+$)/;
for (var i in arr) {
if(!isInt.test(i)){continue;}
}
438ms
For loop, testing on existence rather than length (this fails on sparse arrays).for (var i=0; arr[i]; i++) {} 31ms
For loop, testing on existence rather than length, plus array lookup.for (var i=0; arr[i]; i++) {
var x = arr[i];
}
63ms
For loop, testing on existence rather than length, array lookup is combined with test.for (var i=0, x; x = arr[i++];) {} 46ms
For reference.for (var i=0, len=arr.length; i<len; i++) {
var x = arr[i];
}
47ms
Array.forEach() custom implementation.arr.forEach(function(x){}); 719ms
For reference against forEach().var f=function(x){};
for (var i=0, len=arr.length; i<len; i++) {
f(arr[i]);
}
406ms
Sparse Native Array (length=11258, sporadically populated with 1000 items, looped 100 times)
Basic for loop.for (var i=0; i<sarr.length; i++) {} 344ms
For loop, but caching the length.for (var i=0, len=sarr.length; i<len; i++) {}140ms
While loop that imitates a for loop.var i = 0; while (i<sarr.length) {
i++;
}
328ms
While loop that imitates a for loop, caching the length.var i = 0, len = sarr.length; while (i<len) {
i++;
}
157ms
While loop in reverse, simplifying the test condition.var i=sarr.length; while (i--) {} 78ms
do ... while loop in reverse.var i = sarr.length-1; do { } while (i--);94ms
for loop in reverse.for (var i=sarr.length; i--;) { }93ms
for ... in loopfor (var i in sarr) {}110ms
for ... in loop, with integer testvar isInt = /(^[0-9]$)|(^[1-9][0-9]+$)/;
for (var i in sarr) {
if(!isInt.test(i)){continue;}
}
359ms
Array.forEach() custom implementation.sarr.forEach(function(x){}); 2453ms
For reference against forEach().var f=function(x){};
for (var i=0, len=sarr.length; i<len; i++) {
f(sarr[i]);
}
10922ms
HTML Collection (length=1000, looped 100 times)
Basic for loop.for (var i=0; i<hColl.length; i++) {}2172ms
For loop, but caching the length.for (var i=0, len=hColl.length; i<len; i++) {}15ms
While loop that imitates a for loop.var i = 0; while (i<hColl.length) {
i++;
}
2125ms
While loop that imitates a for loop, caching the length.var i=0, len=hColl.length; while (i<len) {
i++;
}
16ms
While loop in reverse, simplifying the test condition.var i=hColl.length; while (i--) {}15ms
do ... while loop in reverse.var i = hColl.length-1; do { } while (i--);0ms
for loop in reverse.for (var i=hColl.length; i--;) { }16ms
for ... in loopfor (var i in hColl) {} 172ms
for ... in loop, with integer testvar isInt = /(^[0-9]$)|(^[1-9][0-9]+$)/;
for (var i in hColl) {
if(!isInt.test(i)){continue;}
}
484ms
For loop, testing on existence rather than length (this fails on sparse arrays).for (var i=0; hColl[i]; i++) {}1219ms
For loop, testing on existence rather than length, plus array lookup.for (var i=0; hColl[i]; i++) {
var x = hColl[i];
}
2797ms
For loop, testing on existence rather than length, array lookup is combined with test.for (var i=0, x; x = hColl[i++];) {}1406ms
For loop, testing on existence rather than length, array lookup is combined with test, item() instead of array brackets.for (var i=0, x; x = hColl.item(i++);) {} 3203ms
For reference.for (var i=0, len=hColl.length; i<len; i++) {
var x = hColl[i];
}
1453ms

IE 8 Beta 1 / WinXP / 1.95GHZ

Native Array (length=1000, looped 100 times)
Basic for loop.for (var i=0; i<arr.length; i++) {} 46ms
For loop, but caching the length.for (var i=0, len=arr.length; i<len; i++) {}32ms
While loop that imitates a for loop.var i = 0;
while (i<arr.length) {
i++;
}
47ms
While loop that imitates a for loop, caching the length.var i=0, len=arr.length;
while (i<len) {
i++;
}
31ms
While loop in reverse, simplifying the test condition.var i = arr.length; while (i--) {}15ms
While looping by popping values (this fails on sparse arrays).var x;
while (x = arr.pop()) {}
188ms
for ... in loopfor (var i in arr) {}203ms
for ... in loop, with integer testvar isInt = /(^[0-9]$)|(^[1-9][0-9]+$)/;
for (var i in arr) {
if(!isInt.test(i)){continue;}
}
734ms
For loop, testing on existence rather than length (this fails on sparse arrays).for (var i=0; arr[i]; i++) {} 47ms
For loop, testing on existence rather than length, plus array lookup.for (var i=0; arr[i]; i++) {
var x = arr[i];
}
62ms
For loop, testing on existence rather than length, array lookup is combined with test.for (var i=0, x; x = arr[i++];) {} 47ms
For reference.for (var i=0, len=arr.length; i<len; i++) {
var x = arr[i];
}
47ms
Array.forEach() custom implementation.arr.forEach(function(x){}); 610ms
For reference against forEach().var f=function(x){};
for (var i=0, len=arr.length; i<len; i++) {
f(arr[i]);
}
203ms
Sparse Native Array (length=11540, sporadically populated with 1000 items, looped 100 times)
Basic for loop.for (var i=0; i<sarr.length; i++) {} 657ms
For loop, but caching the length.for (var i=0, len=sarr.length; i<len; i++) {}281ms
While loop that imitates a for loop.var i = 0; while (i<sarr.length) {
i++;
}
656ms
While loop that imitates a for loop, caching the length.var i = 0, len = sarr.length; while (i<len) {
i++;
}
266ms
While loop in reverse, simplifying the test condition.var i=sarr.length; while (i--) {}156ms
for ... in loopfor (var i in sarr) {}156ms
for ... in loop, with integer testvar isInt = /(^[0-9]$)|(^[1-9][0-9]+$)/;
for (var i in sarr) {
if(!isInt.test(i)){continue;}
}
641ms
Array.forEach() custom implementation.sarr.forEach(function(x){}); 4656ms
For reference against forEach().var f=function(x){};
for (var i=0, len=sarr.length; i<len; i++) {
f(sarr[i]);
}
3781ms
HTML Collection (length=1000, looped 100 times)
Basic for loop.for (var i=0; i<hColl.length; i++) {}3110ms
For loop, but caching the length.for (var i=0, len=hColl.length; i<len; i++) {}31ms
While loop that imitates a for loop.var i = 0; while (i<hColl.length) {
i++;
}
3109ms
While loop that imitates a for loop, caching the length.var i=0, len=hColl.length; while (i<len) {
i++;
}
16ms
While loop in reverse, simplifying the test condition.var i=hColl.length; while (i--) {}31ms
for ... in loopfor (var i in hColl) {} 281ms
for ... in loop, with integer testvar isInt = /(^[0-9]$)|(^[1-9][0-9]+$)/;
for (var i in hColl) {
if(!isInt.test(i)){continue;}
}
938ms
For loop, testing on existence rather than length (this fails on sparse arrays).for (var i=0; hColl[i]; i++) {} 453ms
For loop, testing on existence rather than length, plus array lookup.for (var i=0; hColl[i]; i++) {
var x = hColl[i];
}
875ms
For loop, testing on existence rather than length, array lookup is combined with test.for (var i=0, x; x = hColl[i++];) {} 453ms
For loop, testing on existence rather than length, array lookup is combined with test, item() instead of array brackets.for (var i=0, x; x = hColl.item(i++);) {} 3906ms
For reference.for (var i=0, len=hColl.length; i<len; i++) {
var x = hColl[i];
}
484ms

IE 6.0 (JScript 5.6) / WinXP / 750MHZ

Native Array (length=1000, looped 100 times)
Basic for loop.for (var i=0; i<arr.length; i++) {}121ms
For loop, but caching the length.for (var i=0, len=arr.length; i<len; i++) {}60ms
While loop that imitates a for loop.var i = 0;
while (i<arr.length) {
i++;
}
110ms
While loop that imitates a for loop, caching the length.var i=0, len=arr.length;
while (i<len) {
i++;
}
60ms
While loop in reverse, simplifying the test condition.var i = arr.length; while (i--) {}50ms
While looping by popping values (this fails on sparse arrays).var x;
while (x = arr.pop()) {}
16694ms
for ... in loopfor (var i in arr) {}781ms
for ... in loop, with integer testvar isInt = /(^[0-9]$)|(^[1-9][0-9]+$)/;
for (var i in arr) {
if(!isInt.test(i)){continue;}
}
2013ms
For loop, testing on existence rather than length (this fails on sparse arrays).for (var i=0; arr[i]; i++) {}141ms
For loop, testing on existence rather than length, plus array lookup.for (var i=0; arr[i]; i++) {
var x = arr[i];
}
250ms
For loop, testing on existence rather than length, array lookup is combined with test.for (var i=0, x; x = arr[i++];) {}140ms
For reference.for (var i=0, len=arr.length; i<len; i++) {
var x = arr[i];
}
170ms
Array.forEach() custom implementation.arr.forEach(function(x){});2945ms
For reference against forEach().var f=function(x){};
for (var i=0, len=arr.length; i<len; i++) {
f(arr[i]);
}
1331ms
Sparse Native Array (length=11009, sporadically populated with 1000 items, looped 100 times)
Basic for loop.for (var i=0; i<sarr.length; i++) {}1241ms
For loop, but caching the length.for (var i=0, len=sarr.length; i<len; i++) {}671ms
While loop that imitates a for loop.var i = 0; while (i<sarr.length) {
i++;
}
1242ms
While loop that imitates a for loop, caching the length.var i = 0, len = sarr.length; while (i<len) {
i++;
}
671ms
While loop in reverse, simplifying the test condition.var i=sarr.length; while (i--) {}471ms
for ... in loopfor (var i in sarr) {}611ms
for ... in loop, with integer testvar isInt = /(^[0-9]$)|(^[1-9][0-9]+$)/;
for (var i in sarr) {
if(!isInt.test(i)){continue;}
}
1762ms
Array.forEach() custom implementation.sarr.forEach(function(x){});11737ms
For reference against forEach().var f=function(x){};
for (var i=0, len=sarr.length; i<len; i++) {
f(sarr[i]);
}
13359ms
HTML Collection (length=1000, looped 100 times)
Basic for loop.for (var i=0; i<hColl.length; i++) {}6349ms
For loop, but caching the length.for (var i=0, len=hColl.length; i<len; i++) {}71ms
While loop that imitates a for loop.var i = 0; while (i<hColl.length) {
i++;
}
6339ms
While loop that imitates a for loop, caching the length.var i=0, len=hColl.length; while (i<len) {
i++;
}
70ms
While loop in reverse, simplifying the test condition.var i=hColl.length; while (i--) {}50ms
for ... in loopfor (var i in hColl) {}2984ms
for ... in loop, with integer testvar isInt = /(^[0-9]$)|(^[1-9][0-9]+$)/;
for (var i in hColl) {
if(!isInt.test(i)){continue;}
}
5017ms
For loop, testing on existence rather than length (this fails on sparse arrays).for (var i=0; hColl[i]; i++) {}4497ms
For loop, testing on existence rather than length, plus array lookup.for (var i=0; hColl[i]; i++) {
var x = hColl[i];
}
8863ms
For loop, testing on existence rather than length, array lookup is combined with test.for (var i=0, x; x = hColl[i++];) {}4516ms
For loop, testing on existence rather than length, array lookup is combined with test, item() instead of array brackets.for (var i=0, x; x = hColl.item(i++);) {}10415ms
For reference.for (var i=0, len=hColl.length; i<len; i++) {
var x = hColl[i];
}
4587ms
Author: "greimer" Tags: "Tech, browsers, dom, javascript, loops, ..."
Send by mail Print  Save  Delicious 
Date: Thursday, 03 Apr 2008 23:09

I've often wished browsers would offer native SAX implementations. SAX is lightweight and fast. Not only that, SAX is easy because it lets you ignore what's not interesting, unlike DOM, where you have to traverse the whole mess and keep it hanging around in memory. SAX also uses callback functions, which any JavaScript programmer should feel comfortable with.

A native SAX implementation in JavaScript would for example let you grab data from RSS feeds over Ajax without loading the entire RSS document into a DOM tree. Or, assuming your XHTML was well-formed, it would let you rapidly query the current document. (Although it wouldn't be able to return references to existing DOM nodes.)

After reading Search and Don't Replace over at John Resig's blog, it got me wondering if you could use that technique as the basis for a SAX parser in JavaScript. Of course there's nothing stopping you from building a SAX parser from scratch in JavaScript, but (methinks) the string tokenizer part of it would be a bit of a beast. However, by taking advantage of the optimization built into JavaScript's RegExp replacement engine, you might just be able to work a nice little souped-up tokenizing engine out of the deal.

So I thought I'd give it a try. What I came up with is nowhere near anything resembling a real-world, valid XML parser. All it knows how to deal with are elements, text nodes and character entities. And not all of the error messages are as helpful as a real world implementation should be. And I'm sure there are plenty of bugs since I banged this out in less than an afternoon. But it ran like scalded cats on a 422kb file. (YMMV depending on what browser you use.) Try it out on this simple XML fragment:

The SAX function looks like this:

doSax(stringToParse,doStartTag,doEndTag,doAttribute,doText);

The callback functions for this example are:

function doStartTag(name){alert("opening tag: "+name);}
function doEndTag(name){alert("closing tag: "+name);}
function doAttribute(name,val){alert("attribute: "+name+'="'+val+'"');}
function doText(str){
    str=str.normalize();
    if(!str){str='[whitespace]';}
    alert("encountered text node: "+str);
}

And here's the code: sax.js. I think that with a little work (i.e. the ability to handle namespaces, comments, and other declarations) this could potentially be usable--maybe not as a full-fledged SAX parser--but a quick and dirty utility for reading XML via Ajax. Hmm, a tag soup SAX-style parser might be nice to have too.

Author: "greimer" Tags: "Tech, javascript, regular_expressions, s..."
Send by mail Print  Save  Delicious 
Date: Thursday, 28 Feb 2008 03:28

The black and white object you're looking at will look different depending which browser you're using, but it should look like a circular target of some sort. It was created using nothing more than CSS's border-radius property and a couple of span tags. All of that to say this: It looks like Safari/Webkit browsers are rendering border-radius quite nicely these days, and Gecko-based browsers aren't far behind, if Firefox's latest public beta means anything. To illustrate this, I've posted some screenshots of a test page I built. This wasn't an exhaustive test for CSS3 border-radius compliance, just an attempt to see where the browsers were with basic support. Only one background image is used (shown below), the rest is pure CSS. (All tests done on the Mac.)

(this is the background image)

Camino 1.5.1 (shown below): This pretty much sums up the entire Mozilla family as of Feb 27th, 2008 in terms of border-radius support. Note the lack of anti-aliasing and the irregular edges. Also note how the background image ignores the boundaries of the rounded corners. Still, it's a commendable effort considering CSS3 isn't actually finalized.

Firefox 3 beta 3 (shown below): What an improvement. The radius forms a nearly perfect, anti-aliased circle (radius=15, width=30) and the background image respects the boundaries now.

Safari 3.0.4 (shown below): Can "perfecter" be used as an adjective? Safari, as usual, is an overachiever, already having released a final version to the public that has decent support for border-radius. In fact, Firefox 3's implementation looks nearly identical to this. (I hope Firefox 3's support isn't just a Mac thing.)

Opera 9.26 (shown below): For reference, this is what it looks like if the browser doesn't support border-radius at all.

For reference, here's the test page.

Author: "greimer" Tags: "Tech, border_radius, browsers, camino, c..."
Send by mail Print  Save  Delicious 
Date: Monday, 11 Feb 2008 23:00

(A followup to my last post.) We're on the brink of releasing a new JavaScript mini-library to sun.com, which we call the reg library. It provides an object named, naturally enough, reg. It stands for register. With it, you can register behaviors, like this:

reg.click('ul.foo > li > a.bar', myFunction);

Once that bit of code runs, regardless of whether the entire DOM has finished loading into the browser, click events on elements matching ul.foo > li > a.bar will be handled by myFunction, which is passed a reference to the active element and the event object. This happens without any DOM traversal, and without any events ever being attached to any <a> elements. Even if the entire contents of document.body are subsequently overwritten by innerHTML, all those new element nodes implicitly inherit the correct behavior. No re-walking of the new DOM subtree ever occurs. No re-attachment of events ever occurs.

How is this even possible?

Two facts conspire to make this feasible. 1) The <body> (document.body) is available almost immediately. 2) Most events bubble. All you need to do is to stand on document.body, and you're privy to almost every event that occurs on the page, right out of the gate. No need to go seeking out the elements you need, they literally bubble their way to you. All you do is grab the event's target and ask the question, does this element, or one of its ancestors, match 'ul.foo > li > a.bar'? If so, run the associated function, if not, ignore it. This is really just event delegation, and it's nothing new, but we've made little use of it on Sun.COM before now.

Limitations, caveats, dangers

I harbor no illusions this is a perfect solution. There are limitations. Besides the fact that not all events bubble, much of time, behavior depends exclusively on preprocessing, especially if you're doing progressive enhancement. You don't want non-JS users to see useless expand/collapse signs or widgets laying around, so you build the widgets only if scripting is enabled. And the only time to build the widgets is onload. And the only way to build the widgets in the right place is... *sigh* traversal. Some of this can fortunately be avoided by relying as much as possible on CSS and making your widget styles depend on a dynamically-added class name, such as body.jsenabled, so there's some workaround potential at least.

There's also an inherent performance limitation. Sitting in the driver's seat on document.body isn't always a relaxing cruise through the countryside. It can easily turn into rush-hour gridlock, with a flood of events each demanding to be checked. For that reason, I dare not use this technique to handle mousemove events. That would cause a veritable torrent of events. Even mouseover events are iffy. We have the capability and it appears to work reasonably well, but time will tell whether it's really viable. Click events, on the other hand, because of their relative infrequency, are a good candidate. Of course, as we develop this thing further, we'll be looking for ways to mitigate performance risks.

So there you go

It isn't live yet, but hopefully will be soon. After this code has been chugging away out there in the wild and woolly world of production Sun.COM for a while, I may post more about this, what works, what doesn't, unexpected wins and losses, etc. Stay tuned.

Author: "greimer" Tags: "Tech, delegation, dom, events, javascrip..."
Send by mail Print  Save  Delicious 
Date: Tuesday, 05 Feb 2008 03:00

As cool as unobtrusive JavaScript is for building the behavioral layer, it's nevertheless based on some pretty kludgy foundations, especially when contrasted with CSS's rather elegant method of declaratively building the presentation layer.

Kludge #1: Waiting for DOM load.

It seems unavoidable. If you want to be unobtrusive, there will be a delay before your functionality is available. Furthermore, DOMContentLoaded and friends don't truly solve the problem. Interestingly, a parallel problem exists in the CSS world: the FOUC (Flash Of Unstyled Content). FOUC is generally not a problem in modern web clients. I wish I could say the same for the "flash of behaviorless content" problem.

Kludge #2: Procedural DOM traversal and event attachment.

Why do I have to seek out the elements that interest me and add behavior, element by element? What a pain. On sufficiently complex pages this means walking the entire tree. If you add new elements as you walk the tree, hall-of-mirrors-style infinite loops and other pitfalls plague you. If innerHTML gets added during the course of the page's life, you have to go back and re-walk those parts of the DOM, re-attaching events as needed. Once again, contrast this with CSS, where the user agent abstracts away the traversal and the attachment of styles, allowing you to declare once--up front--which elements get which styles. Pity we can't do it this way for the behavior layer too.

So what?

Of course these are well known problems. Such is the hand we've been dealt, and tools and techniques exist that make these problems less painful, so why the fuss? In my mind anyway, leaky abstractions on top of kludges aren't an ideal state of affairs, and so I rant. But I also wanted to establish a little background for a future post where I'll describe some tools we're about to deploy on sun.com that, in certain instances, avoid these problems altogether.


[Update]: I've posted a followup with a bit of information about how our new library works.

Author: "greimer" Tags: "Tech, dom, events, fouc, javascript, reg..."
Send by mail Print  Save  Delicious 
Date: Monday, 28 Jan 2008 00:33

We have a function called hasClassName(el, cls) that checks whether a given DOM element has a given class. More and more, we're relying heavily on this function, and on certain pages it can run thousands of times. In these situations a little performance tuning can go a long way, as demonstrated here:

// BEFORE
function hasClassName(el, cls){
  var exp = new RegExp("(^|\\s)"+cls+"($|\\s)");
  return (el.className && exp.test(el.className))?true:false;
}
// AFTER
(function(){
  var c={};//cache regexps for performance
  window.hasClassName=function(el, cls){
    if(!c[cls]){c[cls]=new RegExp("(^|\\s)"+cls+"($|\\s)");}
    return el.className && c[cls].test(el.className);
  }
})();

This simple change cut the function's average runtime in half and reduced the page's overall onload setup time by over 25%! (According to Firebug.) All because it caches regular expressions.

Edit: removed unnecessary ?: operator per Nate's comment.

Author: "greimer" Tags: "Tech, javascript, optimization, regular_..."
Send by mail Print  Save  Delicious 
Date: Monday, 21 Jan 2008 21:01

Python is my spare time language. I wish I had opportunity to use it during my day job, but alas, JavaScript is my day job language. Not that there's anything so terrible about JavaScript, but I get wistful sometimes switching back and forth between being able to use list comprehensions and not being able to use list comprehensions.

So anyway, I wrote a breeder program in Python that breeds little Farkle-playing babies and sets them all off playing each other. The ones that win the most games survive to the next round and get to have little Farkle-playing babies, passing on their Farkle-playing genes with various mutations. The ones that don't win, sadly, become the victims of the garbage-collector. After a few hundred generations or so they got pretty good at Farkle, starting at about 20 rounds per game on average and working their way to about 16 rounds per game on average. (The idea is to get to 10000 in as few turns as possible.) Because it's ultimately based on random numbers (rolls of the dice), Farkle is one of those games where skill level (good risk-tolerance sensibilities) only gives you a marginal advantage, so in retrospect it perhaps isn't the best candidate for an EA.

One thing that struck me about Python versus JavaScript is that with Python, my tendency is to sit and think for a long time, then write a few lines of code. Whereas with JavaScript, my tendency is to spew code prolifically, thinking as I type. I don't know if this speaks more about my skill level in the respective languages, or the nature of the languages themselves. It definitely feels like I burn more keytypes in JavaScript getting ready to do, whereas in Python I burn more keytypes simply doing. Maybe we web developers should push to have Python implemented in web clients as an alternative to JavaScript, if for no other reason than to save our hands from the strain of typing all day.

Author: "greimer" Tags: "Tech, python"
Send by mail Print  Save  Delicious 
Date: Friday, 21 Dec 2007 02:03

Check out this atmospheric phenomenon that appeared around the sun the other day. Do ice crystals in the higher clouds do this?

This is a photo of an interesting solar effect in the clouds.

I originally took the picture because of the bright spot, but in the final pictures the entire halo showed up rather well.

This is a photo of an entire halo appearing around the sun.

Author: "greimer" Tags: "General"
Send by mail Print  Save  Delicious 
Date: Thursday, 20 Dec 2007 04:13

Woo. Leopard arrived yesterday. Gonna install that bad boy as soon as I get a chance.

OS X Leopard has arrived

Author: "greimer" Tags: "Tech, apple, leopard, mac, os_x"
Send by mail Print  Save  Delicious 
Date: Wednesday, 19 Dec 2007 23:33

Strange things are afoot in IE-land. Remember our old friends quirks mode and (almost) standards-compliance mode? There's reason to believe IE8 will introduce yet another rendering mode, and that developers will need to opt-in to this rendering mode if they want IE to break backwards compatibility with its long-entrenched bugs. The question is, how will the opt-in be triggered? A <meta> tag? A version number in the opening <html> tag? An HTTP response header? A conditional comment? The mind boggles.


[Update]: Chris Wilson of the IE team promises more details soon regarding this very thing.


[Update jan/25/08]: And we have a winner: A <meta> tag and/or an HTTP response header. I have no opinion. Too many people smarter than I have already weighed in, and it remains to be seen just exactly how this will all shake out.

Author: "greimer" Tags: "Tech, browsers, ie, ie8, standards"
Send by mail Print  Save  Delicious 
Date: Wednesday, 19 Dec 2007 21:33
Author: "greimer" Tags: "Tech, acid2, browsers, ie, ie8, standard..."
Send by mail Print  Save  Delicious 
Next page
» You can also retrieve older items : Read
» © All content and copyrights belong to their respective authors.«
» © FeedShow - Online RSS Feeds Reader