Sunday, May 23, 2010

Theory of the DOM by Douglas Crockford [My notes]

I just watched the Theory of the DOM video lecture series by Douglas Crockford of Yahoo. Here are the links to all 3 of them


Mr Crockford very nicely tells the history to explain us why/how we got to today's state of browsers, dom and javascript. That aside, I want to note down some of the (theory)things that I want to really really remember from it.

How a typical browser works

You type the URL -> Fetch engine brings the data(or html content from the server) and puts it in cache -> Parse engine parses the html contenct and builds a tree -> Flow engine calculates the position and size of various elements and either augments the same tree or creates a new structure -> Paint engine displays it on the screen

typically, when events(such as Fetch engine downloaded a referenced image) happen,(optionally) a script(js) is executed and then Flow-Paint cycle is repeated

The DOM example

This is IE DOM and not W3C dom. W3C mandates that even the whitespaces between different html elements should be captured in the DOM. Also, notice, though there is no <head> tag in the html, still a head node is introduced in the dom by the browser.

Pointers - what all pointers are maintained for a node by the browser

so, following properties on a node object are available.


Retrieving Nodes
Primary ways to get handle to nodes in DOM are


document.element gives handle to <html> node
document.body gives handle to <body> node

Then, on any node, node.childNodes gives an array of all the children

Once you get a node, you can set/get various properties in it(such as style, class etc).

Creating Node
You can create new nodes by using following

node.cloneNode() : clones a node
node.cloneNode(true) : clones a node and its descendants as well

These newly created notes are not attached to the DOM by default, but you'll explicitly have to attach them using one of following ways
node.insertBefore(new, sibling)
node.insertAfter(new, sibling)
node.replaceChild(new, old)
old.parentNode.replaceChild(new, old)

When you remove a node, its important that you remove all the event handlers associated with it. It is essential because IE6 has a memory leak in garbage collection in that it can not collect cyclically referenced objects even though they are garbage. It is fixed in IE7 though.

There is one more non-standard way. However, almost all good browsers support it. A property called "innerHtml" gives you a handle to the browser html parser, to it you can pass html text and the parser can parse it and attach to the dom.

The browser has an event-driven single threaded, asynchronous programming model. Events are targeted to particular nodes and cause invocation of event-handler functions.
There are mouse events(such as click, double click, mousedown, mousemove, mouseout, mouseover, mouseup) and input events(such as blur, focus, change, keydown, keypress, keyup, reset and submit).

There are 3 ways to associate event-handlers with nodes.

classic: node["on" + type] = function; [works on almost all browsers]
microsoft: node.attachEvent("on" + type, function); [IE only]
w3c: node.addEventListener(type, function, true for trickling/false for bubbling)

Event Handler:
The handler takes an optional event object. But, IE choses not to pass it and use global event object instead. So following boiler-plate code is needed..
 function(e) {
e = e || event; //in case of IE, e is undefined and global event is used
var target = || e.srcElement; //some browsers have target while some have srcElement prop

Trickling and Bubbling
There are two different event dispatch model used by different browsers.
In Trickling model, even is first passed to document root, then to its child and then to its child untill the node where event occured is reached. Any node in the chain may stop the event propagation. Its best to avoid it.
In Bubbling mode, its exactly opposite of trickling, event is first passed to the node where it occured and then to its parent... all the way upto document root.

Let say, you want to cancel bubbling. That is you want to stop propagation of event once the original node handled it. Following is the way
 //two ways
e.cancelBubble = true; //works almost on all browsers
//w3c way
if (e.stopPropagation) {

//note that you need to write both or else use a js platform lib

An event handler can also prevent the browser default action associated with the event(such as submitting a form) with following code..
 //three ways, you need to do all of them
e.returnValue = false; //works on almost all browsers
//w3c way
if(e.preventDefault) {
return false;

Additional JS functions provided by browsers
alert(text), confirm(text), prompt(text,default) - they are blocking calls and must be avoided in case of AJAX application
setTimeout(func, msec) and setInterval(func, msec)

every window/frame/iframs has its own global window(aka self, top, parent) reference

Refs for Inter-window communication
frames[] : child frames and iframes
name : text name of window
opener : reference to open
parent : reference to parent
self/window : reference to this window
top : reference to outermost
open() : open a new window

In general, For security reasons, A script can refer another window if
document.domain === otherwindow.document.domain , also called the same origin policy

Browser Detection
In general its good to avoid navigator.userAgent as not all browsers are honest, instead one is encouraged to feature based detection.

In the end, crockford highly recommends that one should use one of the js platform library such as YUI(or jquery) and they take care of cross browser issues.

Things to Avoid
collections get such as document.forms, document.anchors etc
use of language attribute in script tag
trickling model of event dispatching

No comments:

Post a Comment