jQuery Conference '09 @ Microsoft Cambridge: Strategies for Optimizing JavaScript Performance
Table of Contents
- Background
- Day 1
- 10:00 AM Welcome Welcome and Intro by John Resig (@jereig)
- 10:45 AM Session 1 Recent Changes to jQuery's Internals by John Resig (@jereig)
- 12:00 PM Session 2 jQuery Anti-Patterns for Performance and Compression by Paul Irish (@paulirish) -
- Description
- Recommendations
- Use an object literal rather than blocked anonymous functions with callbacks
- Don't reselect an append() function for event binding
- Use .find() to reduce rather than context
- Be aware of selector engines
- TODO Never use a universal selector
- TODO Evaluate event delegation
- TODO Remove items from the DOM when manipulating
- TODO Use the source as a reference
- Make sure you check that there are elements operated on with a plug-in
- Use YUI compressor (or a compressor)
- Start with <html class="no-js"> to minimize re-flow
- Review ternary operators
- Rate your compression tool
- Alternative: Extending jQuery by Cody Lindley (@codylindley)
- 1:45 PM Session 3 jQuery UI Widget Library by Scott Gonzalez (@scottgonzalez)
- 3:00 PM Session 4 Scaling JavaScript Development with JavaScriptMVC by Justin Meyer (@justinmeyer)
- 3:45 PM Session 5 Extending Ajax Events for All Mankind
- 4:30 PM Session 6 The jQuery UI CSS Framework and ThemeRoller: An In-Depth Overview
- 5:15 PM Session 7 Understanding JavaScript Testing by John Resig (@jereig)
- Day 2
- 10:00 AM Session 1 Load JavaScript Faster by Steve Souders
- 11:00AM Session 2 Query Refactoring by Jonathan Sharp and Brandon Aaron
- 11:45 AM Session 3 Get Involved by Brandon Aaron
- TODO 1:15 PM Performance Discussion
- 2:00 PM Session 5 Advanced jQuery Best Practices by Yehuda Katz (@wycats)
- 3:15 PM Session 6 Building Evented Single Page Applications by John Nunemaker
- 4:15 PM Keynote: jQuery UI
- 4:45 PM Keynote: jQuery
- 5:15 PM Panel Q & A
Background
jQuery Conference '09 @ Microsoft Cambridge, Boston MA http://speakerrate.com/events/172-jquery-conference-2009 #jqcon
Presentations are available at
Outcomes
The following should be considered as separate Strategic Technology projects in Q4.
Use data()
Use live()
Use metadata()
Upgrading to 3.x for performance should be a priority
There are no simple answers for performance improvements
Build a front-end infrastructure
Get involved in the community
Day 1
10:00 AM Welcome Welcome and Intro by John Resig (@jereig)
CAMBRIDGE/jquer912
https://members.oreilly.com/account/login Jason Walsh <jquery09@jwalsh.net>
Free copy of books.
10:45 AM Session 1 Recent Changes to jQuery's Internals by John Resig (@jereig)
Description
http://speakerrate.com/talks/1399-recent-changes-to-jquery-s-internals
The construction and build of jQuery has changed considerably over time - even within the past year has the nature of jQuery changed rather dramatically (with the release of jQuery 1.3, 1.3.1, and 1.3.2).
Notes
This is mostly about 1.3.3.
Sniffing and Support
No more browser sniffing; jQuery.browser is now deprecated.
"Deprecated" means a bad practice; not going to be removed immediately but no schedule set.
jQuery.support now offers workarounds associated with MSIE:
- leading whitespace removal
- opacity support
- cloning permanently binds the events making it a "conjoined twin"
The test: A temporary div that that has several quirks for rendering that need to be worked around.
The question: "Do you do this the right way?", if not then do it the IE way.
Can be added as a new support properties associated with the test. jQuery core only has test that they care about.
All of the tests in support aren't lazy loaded since it only takes 4ms to load.
This mechanism for determining the capacity of an individual browser are more complicated than simple browser sniffing; see the documentation.
TODO Modularity and mobile
Now reflects the breakdown in the documentation.
Should make it easier to dyn load other portions of jQuery as needed.
TODO: querySelectorAll w/ find() http://www.w3.org/TR/selectors-api/
Mobile devices would be limited in the types of selectors and filtering that could be applied.
The use of $.getScript() would continue to use async load of modules with function invocation via the callback.
pdk has a mobile chart; conversations between the mobile device providers and jQuery: "Is getElementsByTagName()" required?"
What are the tradeoffs betwen dependency management and being explicit with imports
Is concat the best option for mobile? Almost certainly for desktop.
TODO: cache limits associated with iPhone 3 + Android + Palm
Embedding of jQuery in the browser likely not needed with the proliferation of the use of CDNs that manage the selection of the libraries and stable versions.
TODO Performance
Sizzle uses an optimal approach to finding the particular selection rather than just relying on the right to left browser selection pattern.
TODO: jQuery Stack Profiler http://github.com/jwalsh/research/issues/#issue/21
TODO: FireUnit profile for CMO to determine top load for page.
ECMAScript 5
Look at the requirements for
No anon functions.
Require the use of constructors (i.e., new String; new RegExp)
FF3.5 and Safari support for JSON parsing or the library support of JSON2.js (Crockford).
TODO Unified Syntax
This could be used for how CMO structures the code. Some of the modules may look better than others.
There would now be a coherent set of test that are used for Function and Array (but with some reduction in the checks used for MSIE).
TODO: .selector / .context rsch
look at jQuery.fn.update as an example case.
- jQuery("div") == jQuery()
Rather than requerying for the document the find() is cached as the root.
- .first() & .last()
filter(":last") would be much slower than .last() .
- .data() now provides a coherent dump of all of the data.
- Document order is now enforced
Performance hit but one of the few libraries are
- Heights are now assumed
- $("#id").find("div") is still faster than $("#id div")
This is just just give the speed of the selector in
Check for any use of something like $("div", "#id") which is just weird.
- append() caches
Now uses fragment caching.
look at aching the same fragment then apply the ids with an attribute.
Caching for very small fragments (250 bytes): this would be something like $("<li>foo</li>").attr("id", "foo" + i).appendTo("ul")
12:00 PM Session 2 jQuery Anti-Patterns for Performance and Compression by Paul Irish (@paulirish) -
Description
If you've seen the results from TaskSpeed, you know that the sexy syntactical sugar of jQuery comes with a few performance disadvantages. jQuery makes it quite easy for you to write some pretty inefficient code, so we'll discuss how to develop in a terse style but with the best possible performance.
Taskspeed was the basic metric; comparisons with other libraries showed that jQuery was the second slowest in 1.3.2.
However, it also took fewest lines of code to create the performance tests.
Recommendations
Standard mechanisms; cache selector, append to fragment outside of the loop.
Use an object literal rather than blocked anonymous functions with callbacks
var CMO = { ruhpInit: function() { }, profileInit: function() { }, }
Don't reselect an append() function for event binding
Use appendTo() with the initial selector then use chaining for the click() bind.
This is just to hold on to a single object. Be wary of not chaining.
Use .find() to reduce rather than context
This is just for readability.
Be aware of selector engines
http://paulirish.com/2008/javascript-css-selector-engine-timeline/
When not in a stylesheet be aware of the differences in the selector engine style; would affect the Souder notes.
Consider just using tag.class on the right side of the selector and just a tag or a class on the left unless the first selector item is an id.
If the first item is just an id consider using the hyper-optimized:
$("#id").find("div")
since this by-passes all of the chunker code and just uses naive browser support.
TODO Never use a universal selector
This is important for :radio without and input as well as $("div > *") for any case.
TODO Evaluate event delegation
If binding an event handler to more than three events consider using live() (contrast with livequery()).
register a selector on $(document).
TODO Remove items from the DOM when manipulating
TODO: jQuery.rule http://flesler.blogspot.com/2007/11/jqueryrule.html
- Grab a reference to the node
- Remove it from the DOM
- Manipulate it
- Add it back in
TODO: Determine how to convert this into a static rules for code review.
TODO Use the source as a reference
Make sure you check that there are elements operated on with a plug-in
Put boilerplate at the top of the plug-in definition:
if (!this.length) { return this; } ;
Use YUI compressor (or a compressor)
TODO: Check to see what the static module would want to run or how this is run with the site.
Compressors will really prefer to use consolidated var references:
var foo = 1, bar = 5, baz = "baz";
Would also be applied for things like constants.
var TRUE = true, FALSE = false, NULL = null, undefined, this = window;
This also minimizes the scope chain traversal (see the Yahoo!
Start with <html class="no-js"> to minimize re-flow
TODO: Determine how this could be a performance gain.
Review ternary operators
TODO: Determine why one would use these structures. Seems complicated for passing values from bound && or || checks or from ternary checks.
Rate your compression tool
Alternative: Extending jQuery by Cody Lindley (@codylindley)
Did not attend the presentation on
http://docs.google.com/present/view?id=ah9wk5hqbhww_50f2nb29f9
but it had a nice summary of the considerations when creating a plug-in.
- create a private scope for $ (http://jsbin.com/uculi/edit#html)
- attach plugin to $.fn alias (http://jsbin.com/uyehe/edit#html)
- add implicit iteration (http://jsbin.com/ilune/edit#html)
- enable chaining (http://jsbin.com/okifa/edit#html)
- add default options (http://jsbin.com/ekogu/edit#html)
- add custom options (http://jsbin.com/ulino/edit#html)
Extra credit: global custom options (http://jsbin.com/eliye/edit#html)
1:45 PM Session 3 jQuery UI Widget Library by Scott Gonzalez (@scottgonzalez)
Description
jQuery has changed the way we write and organize code by defining a sane, flexible API for the DOM. However, sometimes the "find elements, do something" pattern isn't what you're looking for.
Notes
$.widget() as a core support system
How do you initialize a widget with state that can be used
What is a widget:
- something more than simply
- something that maintains state
Nomenclature
- Pass in the function name as a param
Use openDiaglog
- Use prefixes for the UI object type
- Use chaining
- Use pure OO
This is available by default and has constructors but requires a call to _init() (though this will go away).
Question: how does the namespacing work with data().
TODO: Check how the data is getting stored with the constructors with the UI framework.
Create a new widget
Without defining any functionality, first set up all the options that need to be supported.
- Create the widget with the namespacing
cmo.timeline as an example.
- Set up defaults as an object literal
- Use metadata in class if required not with the constructor
- Modify the state of the data in the DOM with metadata
http://plugins.jquery.com/project/metadata
- Use the nomenclature of _ prefixing which is enforced
- Monitor the use of trigger()
How do you clean up all of the changes made as part of converting something to a widget?
destroy: function() {}
is called assuming that the removal originates from jQuery and invokes remove() in the same way as html().
Status
Should be fairly stable. New features are slated for the next released.
Looking at extending base classes to support OO style of development.
Documentation is available outside of the core wiki
There are rules associated with the nomenclature that should reduce some stupidity in the way that objects are called.
Filesize and dependency issues are still being reviewed.
The widget factory is really just a OO factory for all of the default behavior but with bindings into jQuery and how to handle merging of options.
- TODO rsch OAP as alt style for coding
- TODO
3:00 PM Session 4 Scaling JavaScript Development with JavaScriptMVC by Justin Meyer (@justinmeyer)
http://speakerrate.com/talks/1405-scaling-javascript-development-with-javascriptmvc
http://speakerrate.com/talks/1405-scaling-javascript-development-with-javascriptmvc
Description
Developing complex JavaScript applications is a nightmare. Your application has to run on as many browsers as operating systems. Every additional line of code means a slower loading time for your users. Your front-end developers are wasting time waiting for the backend developers to catch up. JavaScriptMVC is a framework that has stolen the best ideas in JavaScript development and integrated them into a single package.
Notes
This is used with client work with Jupiter consulting for single page large applications.
Look at dependency management.
A standard discussion of documentation, using testing, reporting errors, separating functionality, maintainability, quality, CRUD functionality, fixtures (via JSON) parallel development.
This appears to only work in with Rails and CI for the compression.
Takeaway: may as well enforce some best practices even if it involves coordinated with multiple groups at CMO.
This system could never be integrated at CMO:
- assumes single page site
- limited to simple handling of requests for data
- couldn't be fed into CI
Alternative
3:45 PM Session 5 Extending Ajax Events for All Mankind
Description
Provided a mechanism for supporting multiple content types associated with Ajax requests.
Alternative
"Building ARIA-Enabled Widgets With jQuery" by Joe McCann
4:30 PM Session 6 The jQuery UI CSS Framework and ThemeRoller: An In-Depth Overview
Description
Notes
Originally required extensive work for each of the widgets created or would need to use the existing Flora theme.
Only designed for widgets.
TODO: Get a simple theme for CMO without input from Creative. Do this as a non-spec project then roll in the integration.
jQuery UI 1.7 will have some simplified widgets. Would need to be rolled as apart of the project. This uses ThemeRoller 2.0.
Initial theme image support through Google CDN.
Themes only provide color but not position, float, padding, etc.
.ui-widget .ui-widget-header .ui-widget-content
States, overlay, etc. provide additional color and texture.
Uses sprited span classes.
See the .ui-corner-all for a general rounded corner support.
UI Tabs
- Define the namespace for widget
ui-cmo-timeline ui-cmo-timeline-nav ui-cmo-timeline-selected
This will only define the layout.
- Set up the color information
Bind the structural elements to layout components.
.ui-widget-header .ui-widget-content
Multi-scope themes
This is part of the advance selector on the theme builder.
5:15 PM Session 7 Understanding JavaScript Testing by John Resig (@jereig)
Description
Recommendations
JavaScript testing isn't about regression primarily.
Look for quirks in browser than are difficult to remember at all times.
Requirements
Writing own framework is relatively trivial.
- Assertions
Most test suites can be fairly trivial in that it only requires an assertion system.
- Tests
The next level of abstraction lives at the level of a test consisting of multiple assertions.
- Async tests
This allows a queuing system for processing the tests.
Requires setting up the queue.
- Suites
Considerations
Standalone or Runner
- QUnit
- JSUnit
- Selenium
- YUITest
are similar in popularity.
Types of testing
Unit
One method at a time.
- QUnit
There is a session tomorrow.
Supports the core features noted above.
See jqspec.
- JSUnit
Oldest framework and it feels like it.
- YUITest
Likely to be the most popular framework.
Supports async and event simulations that may be better than QUnit which helps in testing UIs.
Look at the YUI 3 syntax for the YUITest 3.
Behavior
Similar to unit but broken by task. Unconfirmed arguments about how the way someone writes behaviors or function assertions and the number of supported types.
- JSSpec
- Screw.Unit
Functional
Browser launcher
The newest entry:
WebDriver - http://code.google.com/p/webdriver/
See the notes for additional options.
Server-side
Look at Crosscheck via issue #24.
js-env has already been implemented at CMO.
Day 2
10:00 AM Session 1 Load JavaScript Faster by Steve Souders
Description
Scripts are the most painful resource to load in your page - they slow down the page more than images, stylesheets, even Flash. Why? Because when browsers start downloading a script, they stop rendering the page and downloading other resources.
Notes
Tools
Using both Page Speed and YSlow! is useful for various tests.
TODO Scripts and splitting
Parallel download now in ff3.5, chrome2…
The tools necessary to support the split are going to be a manual process: do this with the onload tests across all of CMO then apply the logic associated with Doloto:
http://research.microsoft.com/apps/pubs/default.aspx?id=70518
TODO MSN.com parallel scripts (script on element)
createElement("script") then check onreadystatechange.
Check that we're not using <script></script> invocations for ads that would block the parallel downloads in MSIE since this
TODO cmcdn.com blocking options for parallel downloading
Check the work provided by SS on the decision tree for the parallel downloading based on IFRAME or XHR requests.
The async requests could create problems if Web Developers aren't using the correct linkBuilder configuration to indicate the correct domains based on browser behavior.
Ensuring async correct load order
Example given was just for technique 5 in the deck: onloadDone.
$.getScript abstracts this functionality.
Preview release: WordPress optimization tool
Based on Even Faster Websites tool based on jQuery.
This is a sprite generation tool.
This updates the DOM on the fly
11:00AM Session 2 Query Refactoring by Jonathan Sharp and Brandon Aaron
http://speakerrate.com/talks/1415-jquery-refactoring
http://outwestmedia.com/jquery-refactored/
Search jquery.ondata.js from the link above.
Description
With the amount of jQuery code being written, this session takes a practical approach to best practices and patterns for refactoring existing code.
Notes
The example is a simple timer.
<div id=timer> updated by setInterval.
Requirement is to add a pause button.
The progression of the development is to begin to use a custom event and binding in setInterval to just trigger the update.
This uses the data() feature to create custom events and could be used for polling updates associated with widget chunks at CMO for CL or community feed updates.
TODO Apply setData for triggering event changes
Look at decoupling the presentation classes from the data-* classes.
data bound into the DOM with listeners for the particular events: data() triggers setData event as part of jQuery internals (TODO: check the jQuery cookbook).
Custom events are bubbled in 1.3 (part of the Widget Factory); will need to upgrade to a current version before Q4.
TODO onAction plug-in with apply to preserve this
Similar to Live.
- Create action classes
Assume that you have any action-foo
- Bind onAction
Use the plug-in to look for any event (click in the example) assocated with the class name.
- Provide standard action and callbacks for the plug-in
return callback.apply
to support the call to onAction() using $(this) to reference the clicked element.
Questions
Is there a risk when refactoring occurs to remove data specific classes (i.e., the "action-*" classes).
Should the html5 data attributes be used.
Alternative
Font loading, which is likely a low priority for CMO, has slides available at
http://outwestmedia.com/jquery-refactored/jquery-refactored-1.0.zip
11:45 AM Session 3 Get Involved by Brandon Aaron
Description
jQuery has the best JavaScript community around. I'm going to take you behind the scenes of jQuery and share my personal experiences in contributing to jQuery.
Notes
A general discussion of the structure of the jQuery organization.
Try to find the best way to create new features.
Key goal is to just publish something event without a full assessment of the requirements for unit tests, documentation, test support, or coding standards.
Any of the internal projects at CMO could be released assuming that it is solving some problem:
- Bubbles
- Data access for membership types
However, this also requires a deeper understanding of the
dimensions offset has had multiple revisions in order to make it more accurate than other libraries.
The key to survival when contributing is not to over-commit.
Work through the software releases iteratively: push to github, list on jQuery plugins, wait for bug reports.
Take a look at the jQuery Google English group as a first point to address questions that are relevant to the community: http://groups.google.com/group/jquery-en?pli=1 .
See also the jQuery IRC channel as one of the better locations for answering questions:
(setq erc-autojoin-channels-alist '(("freenode.net" "#jquery")))
TODO 1:15 PM Performance Discussion
Description
General discussion of loading options for scripts based on a review
What does the API perform for browsers to limit the damage.
One of the issues with the YUI Loader implementation is that it has no knowledge of how to unblock the script loading.
What constitutes a win?
How to determine when to have the back-end proving the loader script?
This should be an extension
Look at dojo.requires (noted in http://github.com/jwalsh/research/issues/#issue/26).
Notes
Need to determine who has responsibility at CMO for finding the dependencies between functions and downloads in scripts across the site.
Alternatives
2:00 PM Session 5 Advanced jQuery Best Practices by Yehuda Katz (@wycats)
Description
Notes
javascripts/ structuring
Look at an overall application.js file; this would just be the global function or a loader.
Consider structuring according to the type of the application you're running.
Concat
all.js: see the rules associated with how to determine what the load order is required.
Closure at build time
Consider just pulling most of the files into the closure of
(function() { })(jQuery)
or whatever the required files.
Namespace
cmo.
Documentation
Look in particular for custom events.
TODO Configuration
Meta data:
Try this
jQuery(function($) {
});
for simplifying the closure.
Begin using the HTML5 for data structuring for having metadata: use the data- prefix attribute for elements.
Events
For example:
…live("click", function() { …trigger("activated.foo") } );
…live("activated.foo", function() {});
This should also be considered with namespacing.
Dumb server
What should be done for the Rhino parsing of the JSON response with the templating language
Performance
Noted issue with the cache breaking with a query string; won't work. Research already completed.
Split the asset hosts against the new cmcdn.com domain:
s%d.cmcdn.com and s%d.stg2.cmcdn.com
config.actioncontroller.assethost =
This may change the eventual configuration associated with the graphics.base.url to be an asset.host.url
3:15 PM Session 6 Building Evented Single Page Applications by John Nunemaker
4:15 PM Keynote: jQuery UI
Description
Look at jQuery UI Labs.
Ensure that the plugins created at CMO use the widgets plugin from jQuery IU core.
Notes
4:45 PM Keynote: jQuery
- Acquiring a new CDN
- Moving away from Google Groups
- New plugins directory
- 4 conferences next year
- Moving to a non-profit status
5:15 PM Panel Q & A
Questions
Based on moderator.appspot.com.
Answers
documented number of developers actively developed tested actively tested readable