4

I am trying to work out an efficient algorithm for changing a lot of classes on a pile of nodes and I find that I have a great big hole in my understanding of how javascript walks the DOM.

Do browsers/javascript use an elastic racetrack like flash does? or is it more event driven where the whole display is redrawn every time there is a change?

The "elastic racetrack" is a flash paradigm where you imagine a great big loop that flash loops around. During user processing time changes build up and during flash processing time the flash engine races around and applies all the changes - over and over again.

The alternative would be an event model where every time an attribute changes the whole screen is redrawn - this is probably what browsers do but I am not sure.

And I can think of hybrid algorithms where if there are no changes nothing happens - but if there are they are allowed to build up - sort of like dishes on my sink.

Does anyone have a quick description of the algorithm used to handle attribute changes and DOM insertions.

Brenton Thomas
  • 618
  • 1
  • 7
  • 17

1 Answers1

6

Flash's "elastic racetrack" was inherited from the browser. Of course, in browser-land we don't call it that - we call it the event loop.

The history of javascript's event loop started out with progressive GIF and JPEG rendering on Netscape. Progressive rendering - the drawing of partially loaded content - required Netscape to implement an asynchronous download-render engine. When Brendan Eich implemented javascript this asynchronous event loop was already there. So it was a fairly simple task to add another layer to it.

The browser's event loop is therefore something like the following:

    Event loop
        ┌──────────┐
        │          │
        │          │
        │          ▼
        │        check if there's any new ───────▶ parse data
        │        data on the network                    │
        │          │                                    │
        │          ▼                                    │
        │        check if we need to execute  ◀─────────┘
        │        any javascript ──────────────────▶ execute
        │          │                               javascript
        │          ▼                                  │
        │        check if we need to ◀────────────────┘
        │        redraw the page  ──────────────▶ redraw page
        │          │                                   │
        │          │                                   │
        └────◀─────┴─────────────────◀─────────────────┘

The rest, as they say, is history. When Microsoft copied javascript they had to duplicate the event loop to remain compatible with Netscape. So form then on everyone had to do the same to remain compatible with Netscape and IE.

Note that javascript doesn't have any functionality to recurse into the event loop manually (some languages, like tcl for example, can do it) so the browser MUST wait until there is no more javascript to execute before redrawing the page. Page redraws cannot be forced to happen until the end of script.

It is for this reason that calculated values like an element's width or height sometimes return the wrong value when you try to read them immediately after creation - the browser hasn't drawn them yet. The work-around if you really need to execute code after page redraw is to use a setTimeout with a timeout value of 0 to allow the browser to run one round of the event loop.


Additional detail:

There appears to be one exceptional condition that triggers expensive reflows. Note that a reflow is the browser calculating page layout. It's usually triggered if the browser needs to draw a changed page.

When something in the page changes, a reflow calculation is queued - not immediately executed. As in the description above, the reflow will only be executed at the end of the javascript execution. But there is one case that causes the browser to execute reflow calculations immediately: if you try to read any of the calculated values such as width and height.

See this related question for more info: When does reflow happen in a DOM environment?

Community
  • 1
  • 1
slebetman
  • 109,858
  • 19
  • 140
  • 171
  • 1
    [This fiddle](http://jsfiddle.net/fP6vn/) suggests that the re-computations are done before the script block finishes executing, because the coordinates printed definitely change. I wonder if they recompute on relevant property access in this case. – goat Oct 27 '13 at 16:10
  • 1
    Hmm.. it appears that there is one more condition where a reflow is triggered (reflow is the browser calculating object layout without necessarily drawing to the screen, though they tend to happen together). According to my google-fu reflow is triggered when you try to access an element's calculated position. So they recompute when you call the `getBoundingRect` method. See: http://stackoverflow.com/questions/510213/when-does-reflow-happen-in-a-dom-environment – slebetman Oct 27 '13 at 16:22
  • Did you make that formatted ascii text by hand or with software? – goat Oct 27 '13 at 16:44
  • @chris: By hand. It's fairly typical of my longer answers on SO. Though sometimes it penalizes me for being the second (or third) answer. – slebetman Oct 27 '13 at 20:12
  • This is good - it means I can walk a list in the DOM and add and remove a bunch of styling classes without a redraw on each one - just need to check the finer detail on display:none which i have read elsewhere can have reflow issues – Brenton Thomas Oct 27 '13 at 21:03