JavaScript: An Experiment January 13, 2010 Willi Gamboa [email_address]
Objective <ul><li>Find out how expensive interactions between JavaScript and the DOM are, as compared to operations that a...
Hypothesis <ul><li>If you are going to perform complex manipulations on an </li></ul><ul><li>element, it would be more eff...
Document Fragments <ul><li>Similar in concept to the hypothesis </li></ul><ul><li>If a document fragment is appended to an...
Use Case: GOLF Leaderboard
Use Case: GOLF Leaderboard <ul><li>Sorting/resorting is good </li></ul><ul><ul><li>A div object is created and filled outs...
Procedure <ul><li>Create a  mini-application  to simulate the two cases: </li></ul><ul><ul><li>Case 1 </li></ul></ul><ul><...
Examine the Code <ul><li>Some best practices and tidbits along the way </li></ul><ul><li>View the  script source </li></ul>
Preserve the Namespace <ul><li>Enclose code in a self-executing anonymous function: </li></ul><ul><li>(function ($) </li><...
Scoping <ul><li>(function ($) </li></ul><ul><li>{ </li></ul><ul><li>var localVariable = ' is in the local scope of the ano...
The Application Singleton <ul><li>A singleton is an object that: </li></ul><ul><li>Can only have one instance </li></ul><u...
Watch out for This <ul><li>window.domTest = </li></ul><ul><li>{ </li></ul><ul><li>defaultSettings : {}, </li></ul><ul><li>...
Objects with Privacy <ul><li>Aka, the Module </li></ul><ul><li>Used by the Rails team for polls </li></ul><ul><li>var modu...
Objects with Privacy <ul><li>var instance = module (); </li></ul><ul><li>alert (instance.publicProperty)     not secret <...
Settings/Parameters <ul><li>Defining settings as JSON makes it clear what the parameter names are </li></ul><ul><li>Parame...
Extending Objects <ul><li>init : function (currentSettings) </li></ul><ul><li>{ </li></ul><ul><li>this.settings = $.extend...
Array Definition Trick <ul><li>It’s easier to define an array this way: </li></ul><ul><li>colorArray : ' red orange yellow...
The live () Event Listener <ul><li>/* This event listener is declared as the DOM is loading */ </li></ul><ul><li>$ (' .but...
How live () works <ul><li>Event delegation </li></ul><ul><ul><li>Event bubbling </li></ul></ul><ul><ul><li>Listen for an e...
How live () works <ul><li>Take </li></ul><ul><li><ul id=&quot;ul&quot;> </li></ul><ul><li><li>1</li> </li></ul><ul><li><li...
How live () works <ul><li>var addListener = function (element, eventType, handler) </li></ul><ul><li>{ </li></ul><ul><li>i...
How live () works <ul><li>addListener (window, 'load', function () </li></ul><ul><li>{ </li></ul><ul><li>var ul = document...
How live () works <ul><li>Test it  in Firefox and IE </li></ul>
How live () works <ul><li>Caveat:  Take </li></ul><ul><li><div> </li></ul><ul><ul><li><ul id=&quot;ul&quot;> </li></ul></u...
The Element Manipulations <ul><li>process : function (remove) </li></ul><ul><li>{ </li></ul><ul><li>if (remove) { domTest....
Observe the Results <ul><li>Get the average and aggregate completion times of  process () </li></ul><ul><li>Qualification:...
Conclusion <ul><li>Do the results prove the hypothesis? </li></ul><ul><li>Just how expensive are interactions between Java...
Upcoming SlideShare
Loading in …5
×

Javascript Experiment

942 views

Published on

Find out how expensive interactions between JavaScript and the DOM are, as compared to operations that are purely in JavaScript

0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
942
On SlideShare
0
From Embeds
0
Number of Embeds
15
Actions
Shares
0
Downloads
8
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Javascript Experiment

  1. 1. JavaScript: An Experiment January 13, 2010 Willi Gamboa [email_address]
  2. 2. Objective <ul><li>Find out how expensive interactions between JavaScript and the DOM are, as compared to operations that are purely in JavaScript </li></ul>
  3. 3. Hypothesis <ul><li>If you are going to perform complex manipulations on an </li></ul><ul><li>element, it would be more efficient to: </li></ul><ul><ul><li>Detach the element from the DOM first </li></ul></ul><ul><ul><li>or create a new element outside of the DOM </li></ul></ul><ul><ul><li>Perform the complex manipulations on the element </li></ul></ul><ul><ul><li>Reattach/attach the element to the DOM </li></ul></ul>
  4. 4. Document Fragments <ul><li>Similar in concept to the hypothesis </li></ul><ul><li>If a document fragment is appended to an element that is part of the DOM, all the child nodes of the fragment will be moved to the child list of the element natively </li></ul><ul><li>var fragment = document.createDocumentFragment (); </li></ul><ul><li>See John Resig’s demo </li></ul>
  5. 5. Use Case: GOLF Leaderboard
  6. 6. Use Case: GOLF Leaderboard <ul><li>Sorting/resorting is good </li></ul><ul><ul><li>A div object is created and filled outside of the DOM, after which it is appended to the DOM </li></ul></ul><ul><li>Creating/refreshing the leaderboard is good, but could be slightly optimized </li></ul><ul><ul><li>The leaderboard’s three sections are appended to the DOM separately </li></ul></ul><ul><ul><li>Make only one append to the DOM instead </li></ul></ul>
  7. 7. Procedure <ul><li>Create a mini-application to simulate the two cases: </li></ul><ul><ul><li>Case 1 </li></ul></ul><ul><ul><li>Element stays attached to the DOM all throughout the process </li></ul></ul><ul><ul><li>Case 2 </li></ul></ul><ul><ul><li>Element is detached from the DOM, then reattached </li></ul></ul>
  8. 8. Examine the Code <ul><li>Some best practices and tidbits along the way </li></ul><ul><li>View the script source </li></ul>
  9. 9. Preserve the Namespace <ul><li>Enclose code in a self-executing anonymous function: </li></ul><ul><li>(function ($) </li></ul><ul><li>{ </li></ul><ul><li>/* Code goes here */ </li></ul><ul><li>var ul = $ (' #ul '); </li></ul><ul><li>}) (jQuery); </li></ul><ul><li>The jQuery object is passed to the $ parameter </li></ul><ul><li>This inner $ will protect from namespace conflict if $ has already been defined globally by some other code </li></ul>
  10. 10. Scoping <ul><li>(function ($) </li></ul><ul><li>{ </li></ul><ul><li>var localVariable = ' is in the local scope of the anonymous function because of the var declaration '; </li></ul><ul><li>window.globalVariable = ' is in the global scope, which is the same as the window scope '; </li></ul><ul><li>}) (jQuery); </li></ul>
  11. 11. The Application Singleton <ul><li>A singleton is an object that: </li></ul><ul><li>Can only have one instance </li></ul><ul><li>Is defined with an object literal, the same way as JSON </li></ul><ul><li>window.domTest = </li></ul><ul><li>{ </li></ul><ul><li>defaultSettings : {}, </li></ul><ul><li>init : function (settings) {}, </li></ul><ul><li>startTest : function (remove) {}, </li></ul><ul><li>process : function (remove) {} </li></ul><ul><li>}; </li></ul>
  12. 12. Watch out for This <ul><li>window.domTest = </li></ul><ul><li>{ </li></ul><ul><li>defaultSettings : {}, </li></ul><ul><li>init : function (settings) {}, </li></ul><ul><li>startTest : function (remove) {}, </li></ul><ul><li>process : function (remove) {} </li></ul><ul><li>}; </li></ul>Instant IE Death
  13. 13. Objects with Privacy <ul><li>Aka, the Module </li></ul><ul><li>Used by the Rails team for polls </li></ul><ul><li>var module = function () </li></ul><ul><li>{ </li></ul><ul><li>var privateProperty = ' secret '; </li></ul><ul><li>var publicProperty = ' not secret '; </li></ul><ul><li>var privateMethod = function () {}; </li></ul><ul><li>var publicMethod = function () {}; </li></ul><ul><li>return </li></ul><ul><li>{ </li></ul><ul><li>publicProperty : publicProperty, </li></ul><ul><li>publicMethod : publicMethod </li></ul><ul><li>} </li></ul><ul><li>}; </li></ul>
  14. 14. Objects with Privacy <ul><li>var instance = module (); </li></ul><ul><li>alert (instance.publicProperty)  not secret </li></ul><ul><li>alert (instance.publicMethod)  function () {} </li></ul><ul><li>alert (instance.privateProperty)  instance.privateProperty is undefined </li></ul><ul><li>alert (instance.privateMethod)  instance.privateMethod is undefined </li></ul>
  15. 15. Settings/Parameters <ul><li>Defining settings as JSON makes it clear what the parameter names are </li></ul><ul><li>Parameter order is not important </li></ul><ul><li>defaultSettings : </li></ul><ul><li>{ </li></ul><ul><li>iterations : 30 , </li></ul><ul><li>liAmount : 50 , </li></ul><ul><li>colorArray : ' red orange yellow green blue indigo violet '.split (' '), </li></ul><ul><li>liTemplate : ' <li><a href=&quot;#&quot;><strong>This</strong> is a <em>line</em> of <u>text</u> with a #{color} background color.</a></li> ', </li></ul><ul><li>colorPattern : new RegExp (' #{.*?} ', ' g ') </li></ul><ul><li>}, </li></ul>
  16. 16. Extending Objects <ul><li>init : function (currentSettings) </li></ul><ul><li>{ </li></ul><ul><li>this.settings = $.extend ({}, this.defaultSettings, currentSettings); </li></ul><ul><li>… </li></ul><ul><li>}, </li></ul><ul><li>Merge currentSettings over this.defaultSettings without changing the values of this.defaultSettings </li></ul><ul><li>If currentSettings is undefined, jQuery makes this.settings = this.defaultSettings </li></ul>
  17. 17. Array Definition Trick <ul><li>It’s easier to define an array this way: </li></ul><ul><li>colorArray : ' red orange yellow green blue indigo violet '.split (' ') </li></ul><ul><li>Instead of: </li></ul><ul><li>colorArray : new Array (' red ', ' orange ', ' yellow ', ' green ', ' blue ', ' indigo ', ' violet ') </li></ul>
  18. 18. The live () Event Listener <ul><li>/* This event listener is declared as the DOM is loading */ </li></ul><ul><li>$ (' .button ').live (' click ', function (event) </li></ul><ul><li>{ </li></ul><ul><li>switch ($ (this).attr (' rel ')) </li></ul><ul><li>{ </li></ul><ul><li>case ' Test 1 ': </li></ul><ul><li>domTest.startTest (false); </li></ul><ul><li>break; </li></ul><ul><li>}; </li></ul><ul><li>event.preventDefault (); </li></ul><ul><li>}); </li></ul>
  19. 19. How live () works <ul><li>Event delegation </li></ul><ul><ul><li>Event bubbling </li></ul></ul><ul><ul><li>Listen for an event at a higher level in the ancestor tree </li></ul></ul><ul><ul><li>jQuery’s live () places its event listener on the document object, which is always present </li></ul></ul><ul><ul><li>This means that live () and its unbinder, die () don’t have to wait for the </li></ul></ul><ul><ul><li>$ (document).ready event to work correctly </li></ul></ul>
  20. 20. How live () works <ul><li>Take </li></ul><ul><li><ul id=&quot;ul&quot;> </li></ul><ul><li><li>1</li> </li></ul><ul><li><li>2</li> </li></ul><ul><li><li>3</li> </li></ul><ul><li></ul> </li></ul><ul><li><input id=&quot;button&quot; type=&quot;button&quot; value=&quot;Add li&quot; /> </li></ul>
  21. 21. How live () works <ul><li>var addListener = function (element, eventType, handler) </li></ul><ul><li>{ </li></ul><ul><li>if (element.addEventListener) </li></ul><ul><li>{ </li></ul><ul><li>element.addEventListener (eventType, handler, false); </li></ul><ul><li>} </li></ul><ul><li>else if (element.attachEvent) </li></ul><ul><li>{ </li></ul><ul><li>element.attachEvent (' on ' + eventType, handler); </li></ul><ul><li>} </li></ul><ul><li>else </li></ul><ul><li>{ </li></ul><ul><li>element [' on ' + eventType] = handler; </li></ul><ul><li>} </li></ul><ul><li>}; </li></ul>
  22. 22. How live () works <ul><li>addListener (window, 'load', function () </li></ul><ul><li>{ </li></ul><ul><li>var ul = document.getElementById ('ul'); </li></ul><ul><li>addListener (ul, ' mouseover ', function (event) </li></ul><ul><li>{ </li></ul><ul><li>var eventSource = event.target ? event.target : event.srcElement; </li></ul><ul><li>if (eventSource.nodeName.toLowerCase () == ' li ') </li></ul><ul><li>{ </li></ul><ul><li>eventSource.style.backgroundColor = ' red '; </li></ul><ul><li>} </li></ul><ul><li>}); </li></ul><ul><li>addListener (document.getElementById ('button'), 'click', function () </li></ul><ul><li>{ </li></ul><ul><li>ul.appendChild (document.createElement ('li')); </li></ul><ul><li>}); </li></ul><ul><li>}); </li></ul>
  23. 23. How live () works <ul><li>Test it in Firefox and IE </li></ul>
  24. 24. How live () works <ul><li>Caveat: Take </li></ul><ul><li><div> </li></ul><ul><ul><li><ul id=&quot;ul&quot;> </li></ul></ul><ul><ul><li><li>1</li> </li></ul></ul><ul><ul><li><li>2</li> </li></ul></ul><ul><ul><li><li>3</li> </li></ul></ul><ul><ul><li></ul> </li></ul></ul><ul><li></div> </li></ul><ul><li>where “live” is applied to the <div> instead of the <ul> for a mouseover event </li></ul><ul><li>If <ul> has a separate mouseover listener that returns false , no <li> mouseover event will reach the “live” listener on the <div> </li></ul><ul><li>“ live” won’t work in this case </li></ul>
  25. 25. The Element Manipulations <ul><li>process : function (remove) </li></ul><ul><li>{ </li></ul><ul><li>if (remove) { domTest.ul.remove (); } </li></ul><ul><li>for (var i = 0 ; i < this.settings.liAmount; i++) </li></ul><ul><li>{ </li></ul><ul><li>var randomIndex = Math.round (Math.random () * this.colorIndexCount); </li></ul><ul><li>var color = this.settings.colorArray [randomIndex]; </li></ul><ul><li>var li = $ (this.settings.liTemplate.replace (this.settings.colorPattern, color)); </li></ul><ul><li>li.appendTo (domTest.ul); </li></ul><ul><li>var anchor = li.find (' a '); </li></ul><ul><li>anchor.css (' color ', ' #fff '); </li></ul><ul><li>anchor.css (' font-size ', ' 18px '); </li></ul><ul><li>anchor.css (' text-decoration ', ' none '); </li></ul><ul><li>li.data (' color ', color); </li></ul><ul><li>} </li></ul><ul><li>if (remove) { domTest.body.append (domTest.ul); } </li></ul><ul><li>} </li></ul>
  26. 26. Observe the Results <ul><li>Get the average and aggregate completion times of process () </li></ul><ul><li>Qualification: If the maximum completion time of a sample is inordinately greater than the average completion time (e.g., 500 ms vs. 38 ms ), then the results for that run are invalid </li></ul>
  27. 27. Conclusion <ul><li>Do the results prove the hypothesis? </li></ul><ul><li>Just how expensive are interactions between JavaScript and the DOM? </li></ul><ul><li>Page load delay: a comparable frame of reference? </li></ul><ul><ul><li>Amazon: 100 millisecond delay = loss of 1% in sales </li></ul></ul><ul><ul><li>Yahoo: 400 millisecond delay = loss of 5-9% in full page traffic </li></ul></ul><ul><ul><li>Google: 500 millisecond delay = 20% fewer searches </li></ul></ul><ul><ul><li>GOLF leaderboard: JavaScript refreshes can be considered new page loads </li></ul></ul>

×