How SproutCore loads views

I’ve been asked this question several times in the last few days so I thought I might help to put an explanation about how SproutCore handles binding HTML to JavaScript.  If you’ve ever tried to build a JavaScript app before, you probably know that the biggest cost when you load the browser is hooking up all of the JavaScript and event bindings to the HTML in you web page.  There are actually four things that are real performance hogs in a browser:

 

  1. Creating DOM.  If you want to build new HTML to replace existing HTML it will be 10-20x slower than simply having the HTML baked into the page on load in the first place. 
  2. Searching the DOM.  In general browsers are not super fast at finding elements in the DOM except for those named by IDs.  Even for those browsers with XPath support, the cost is nontrivial.
  3. Adding JS properties to DOM elements.  Almost all libraries out there today work by patching the HTMLElement prototype to add nifty utilities like $().  The only problem is that this trick does not work in IE, so instead you have to monkey patch every single DOM element when you touch it.  In IE6, that’s a 10msec penalty for every element.
  4. Binding to events.  Every time you add an event listener in the web browser, its another penalty.

 

Oddly enough most JS frameworks use techniques that hit all four of these bottlenecks, mostly because they want to “attach” to your HTML on page load.  If you’re adding just a few wiz-bang Ajaxy/Web2.0 effect this is not a problem, but once you start building entire applications with dozens or hundreds of views, these little costs add up.

The SproutCore Solution

The first versions of SproutCore actually faced these same problems as well.  In fact, I spent the better part of 6 months working through all of them.  Now SproutCore takes a decidedly non-traditional approach to avoid these issues.  Here is what happens when you build a SproutCore app:

 

  1. Static HTML is pre-generated.  Whenever possible, SproutCore views expect the HTML they will be managing to be pregenerated in the main document HTML.  The only time SproutCore views create new content is usually for collection views such as lists, grids, and tables.  By using this approach, SproutCore can use the most efficient code path in the browser (parsing on page load) to build out any DOM that will be required by the app.
  2. HTML is consumed on demand.  Most HTML and JS views are not needed right when a page loads.  It might be a hidden dialog or popup for example, that will not be used until later in the app.  Rather than finding all of these DOM elements right away, most HTML is stored in a single div called “resources”, which is pulled out of the main document as soon as it loads.  The SproutCore views and the DOM they use are consumed only when they are actually needed by your application.  
  3. Views manage DOM; DOM is not to be modified.  SproutCore views wrap DOM objects and reproduce most of the common DOM API you might use.  The idea is that you can generally work with SC.View objects and let them take care of the DOM elements for you.  The view’s in turn, take great pains to avoid actually adding properties to the DOM elements, avoiding the heavy performance penalty that comes along with it.
  4. Events are managed at the window level.  Instead of listening for an onclick() handler on 50 different elements on your page, SproutCore apps list to exactly 6 events on the window object instead.  SproutCore code then takes care of routing those events to the proper SC.View instance to handle the event.  Views themselves do not need to register for events to receive them; they just implement the appropriately named responder methods.  This means you can respond to as many events as you want on your page and you won’t pay any performance penalty on page load.

 

Overall SproutCore views definitely favor performance over convenience.  To make views convenient as well, SproutCore has the view builder system which uses to Ruby code to generate both the HTML and JavaScript for your views so you don’t have to.  This generally makes views both easy to use and performant.

 

Discussion Area - Leave a Comment