From 5a50bbd970a6f3847587486652dd85f9f88516d3 Mon Sep 17 00:00:00 2001
From: Bob Holt
Date: Mon, 15 Oct 2012 12:13:17 -0400
Subject: [PATCH] moving /performance /faq /code-organization code examples to
md
---
.../beware-anonymous-functions.md | 4 +-
page/code-organization/concepts.md | 27 +++++++------
.../code-organization/dont-repeat-yourself.md | 4 +-
page/faq/add_keyboard_navigation.md | 38 +++++++++----------
page/faq/enable_the_back_button.md | 16 ++++----
page/performance/append-outside-loop.md | 12 +++---
page/performance/cache-loop-length.md | 5 ++-
page/performance/clever-conditionals.md | 4 +-
.../detach-elements-before-work-with-them.md | 4 +-
.../dont-act-on-absent-elements.md | 5 +--
page/performance/optimize-selectors.md | 16 ++++----
page/performance/read-the-source.md | 2 +-
.../use-stylesheets-for-changing-css.md | 4 +-
page/performance/variable-definition.md | 8 ++--
14 files changed, 76 insertions(+), 73 deletions(-)
diff --git a/page/code-organization/beware-anonymous-functions.md b/page/code-organization/beware-anonymous-functions.md
index f7712b4e..b0432d71 100644
--- a/page/code-organization/beware-anonymous-functions.md
+++ b/page/code-organization/beware-anonymous-functions.md
@@ -6,7 +6,7 @@ attribution: jQuery Fundamentals
Anonymous functions bound everywhere are a pain. They're difficult to debug,
maintain, test, or reuse. Instead, use an object literal to organize and name
your handlers and callbacks.
-
+```
// BAD
$(document).ready(function() {
$('#magic').click(function(e) {
@@ -37,4 +37,4 @@ var PI = {
};
$(document).ready(PI.onReady);
-
+```
\ No newline at end of file
diff --git a/page/code-organization/concepts.md b/page/code-organization/concepts.md
index 01799175..9f78f06f 100644
--- a/page/code-organization/concepts.md
+++ b/page/code-organization/concepts.md
@@ -23,7 +23,7 @@ some concepts that are common to all good code organization patterns.
- Despite jQuery's DOM-centric nature, JavaScript applications are not all
about the DOM. Remember that not all pieces of functionality need to — or
should — have a DOM representation.
-- Units of functionality should be [loosely coupled](http://en.wikipedia.org/wiki/Loose_coupling), that is,
+- Units of functionality should be [loosely coupled](http://en.wikipedia.org/wiki/Loose_coupling), that is,
a unit of functionality should be able to exist on its own, and communication between
units should be handled via a messaging system such as custom events or
pub/sub. Stay away from direct communication between units of functionality
@@ -45,7 +45,8 @@ doesn't offer any privacy for properties or methods, but it's useful for
eliminating anonymous functions from your code, centralizing configuration
options, and easing the path to reuse and refactoring.
-
+```
+// An object literal
var myFeature = {
myProperty : 'hello',
@@ -66,7 +67,7 @@ options, and easing the path to reuse and refactoring.
myFeature.myMethod(); // logs 'hello'
myFeature.init({ foo : 'bar' });
myFeature.readSettings(); // logs { foo : 'bar' }
-
+```
The object literal above is simply an object assigned to a variable. The object
has one property and several methods. All of the properties and methods are
@@ -77,7 +78,7 @@ be called before the object is functional.
How would we apply this pattern to jQuery code? Let's say that we had this code
written in the traditional jQuery style:
-
+```
// clicking on a list item loads some content
// using the list item's ID and hides content
// in sibling list items
@@ -97,7 +98,7 @@ written in the traditional jQuery style:
);
});
});
-
+```
If this were the extent of our application, leaving it as-is would be fine. On
the other hand, if this was a piece of a larger application, we'd do well to
@@ -106,7 +107,8 @@ want to move the URL out of the code and into a configuration area. Finally, we
might want to break up the chain to make it easier to modify pieces of the
functionality later.
-
+```
+// Using an object literal for a jQuery feature
var myFeature = {
init : function(settings) {
myFeature.config = {
@@ -166,7 +168,7 @@ functionality later.
};
$(document).ready(myFeature.init);
-
+```
The first thing you'll notice is that this approach is obviously far longer
than the original -- again, if this were the extent of our application, using an
@@ -194,8 +196,8 @@ The module pattern overcomes some of the limitations of the object literal,
offering privacy for variables and functions while exposing a public API if
desired.
-
-
+```
+// The module pattern
var feature =(function() {
// private variables and functions
@@ -224,7 +226,7 @@ desired.
feature.sayPrivateThing();
// logs 'secret' and changes the value
// of privateThing
-
+```
In the example above, we self-execute an anonymous function that returns an
object. Inside of the function, we define some variables. Because the variables
@@ -243,7 +245,8 @@ Below is a revised version of the previous example, showing how we could create
the same feature using the module pattern while only exposing one public method
of the module, `showItemByIndex()`.
-
+```
+// Using the module pattern for a jQuery feature
$(document).ready(function() {
var feature = (function() {
var $items = $('#myFeature li'),
@@ -297,4 +300,4 @@ of the module, `showItemByIndex()`.
feature.showItemByIndex(0);
});
-
+```
diff --git a/page/code-organization/dont-repeat-yourself.md b/page/code-organization/dont-repeat-yourself.md
index 2b5962d5..8372b3b9 100644
--- a/page/code-organization/dont-repeat-yourself.md
+++ b/page/code-organization/dont-repeat-yourself.md
@@ -4,7 +4,7 @@ attribution: jQuery Fundamentals
---
Don't repeat yourself; if you're repeating yourself, you're doing it wrong.
-
+```
// BAD
if ($eventfade.data('currently') != 'showing') {
$eventfade.stop();
@@ -25,4 +25,4 @@ $.each($elems, function(i,elem) {
elem.stop();
}
});
-
+```
\ No newline at end of file
diff --git a/page/faq/add_keyboard_navigation.md b/page/faq/add_keyboard_navigation.md
index b32e4941..16962953 100644
--- a/page/faq/add_keyboard_navigation.md
+++ b/page/faq/add_keyboard_navigation.md
@@ -1,6 +1,6 @@
---
title: Adding Keyboard Navigation
-attribution: Remy Sharp
+attribution: Remy Sharp
status: needswork
editrequired: 2
source: http://jqueryfordesigners.com/adding-keyboard-navigation/
@@ -34,17 +34,17 @@ Then a keyboard key is pressed the event break into three separate events, which
So I’m going to use the last phase of the events and use the keyup event.
-
+```
$(document.documentElement).keyup(function (event) {
// handle cursor keys
});
-
+```
Note that all event handlers in jQuery, such as click, keyup, mouseover, etc receive an event [argument](http://en.wikipedia.org/wiki/Parameter_(computer_science)) - which I’ve captured under the variable name event.
The left and right key codes are 37 and 39 respectively. So we only want to action the slide if these keys are pressed, so we’ll check the keyCode property on the event - this property is [very well supported in browsers](http://www.quirksmode.org/js/keys.html):
-
+```
$(document.documentElement).keyup(function (event) {
// handle cursor keys
if (event.keyCode == 37) {
@@ -53,7 +53,7 @@ The left and right key codes are 37 and 39 respectively. So we only want to acti
// go right
}
});
-
+```
##Triggering the Click on the Right Link
@@ -61,7 +61,7 @@ Triggering a click event is easy, but the problem we have to solve is finding th
In some cases the current class might be on list element, which would make the navigating slightly easier, but in this case the markup looks a bit like this:
-
+```
<div class="coda-slider-wrapper">
<ul>
<li><a class="current" href="#1">1</a></li>
@@ -71,31 +71,31 @@ In some cases the current class might be on list element, which would make the n
<li><a href="#5">5</a></li>
</ul>
</div>
-
+```
In the case above, the “next” link is #2. Currently there’s no previous available, but we’ll let jQuery handle this for us.
To find the next link, first we need to grab the link that’s currently selected:
-
+```
$('.coda-slider-wrapper ul a.current')
-
+```
Next we need to move up the tree (to the li element) and move to the next element and then back down to the a element to trigger a click.
-
+```
$('.coda-slider-wrapper ul a.current')
.parent() // moves up to the li element
.next() // moves to the adjacent li element
.find('a') // moves down to the link
.click(); // triggers a click on the next link
-
+```
Since jQuery continues to allow chained methods to work even if there’s no elements found, we can also use prev() in the place of next() when current is on the first element and the code will work just fine still.
Let’s plug this code in to the keyboard event handler:
-
+```
$(document.documentElement).keyup(function (event) {
// handle cursor keys
if (event.keyCode == 37) {
@@ -111,11 +111,11 @@ Let’s plug this code in to the keyboard event handler:
$('.coda-slider-wrapper ul a.current').parent().next().find('a').click();
}
});
-
+```
This code can be simplified since a lot of it is repetitive aside from the ‘next’ and ‘prev’. If you’re happy for slightly more complicated code, then use the code below, otherwise stick with the code above.
-
+```
$(document.documentElement).keyup(function (event) {
var direction = null;
@@ -132,7 +132,7 @@ This code can be simplified since a lot of it is repetitive aside from the ‘ne
$('.coda-slider-wrapper ul a.current').parent()[direction]().find('a').click();
}
});
-
+```
##Where does this all go?
@@ -142,15 +142,15 @@ Since we’re going in after the slider plugin is run, so it should go *directly
In Mathieu’s code, he had the following:
-
+```
$().ready(function() {
$('#coda-slider-1').codaSlider();
});
-
+```
Note that $().ready is the same as $(document).ready (though it’s not a style I would personally use). *Directly* after the plugin (i.e. before the });) results in the following code:
-
+```
$().ready(function() {
$().ready(function() {
$('#coda-slider-1').codaSlider();
@@ -172,7 +172,7 @@ $().ready(function() {
}
});
});
-
+```
You can see this all [in action in the demo](http://static.jqueryfordesigners.com/demo/keyboard-nav.html), and be sure to use the left and right keyboard cursor keys to see the demo working.
diff --git a/page/faq/enable_the_back_button.md b/page/faq/enable_the_back_button.md
index 128b5f13..00cea9f9 100644
--- a/page/faq/enable_the_back_button.md
+++ b/page/faq/enable_the_back_button.md
@@ -34,15 +34,15 @@ This process was our original code, and most of it needs to stay in place. The c
So we listen for the hashchange event, just like we might listen for a click event:
-
+```
$(window).bind('hashchange', function(){
//do some magic
});
-
+```
Now we move all of the original code from the click handler in to this new event listener. I’ve copied this code in, and marked in bold which lines we’ll need to change:
-
+```
$(window).bind('hashchange', function(){
tabContainers.hide();
tabContainers.filter(this.hash).show();
@@ -50,7 +50,7 @@ $('div.tabs ul.tabNavigation a').removeClass('selected');
$(this).addClass('selected');
return false;
});
-
+```
At this point all the references to this need to change, because in our original version this referred to the link that had be clicked. Now we need to determine the link based on the window URL. We can get the newly navigated URL using window.location. This is an object that represents part of the URL, and as such, gives as just the hash by itself:window.location.hash. This is good.
@@ -60,9 +60,9 @@ Next we need to address how we can target the appropriate tab to add the selecte
Since we don’t have this to target the right tab, we need to find the element using jQuery. Since we have the hash, we can use this to find the tab link. We can use the “hash” attribute selector like this:
-
+```
$('a[hash=#first]')
-
+```
Therefore we can substitute our hash variable in to the ‘#first’ part of the selector above, and now we’ll have the right element to add the selected class.
@@ -74,7 +74,7 @@ Then one last change to make to our code - we need to trigger the hashchange eve
Our final code looks like this:
-
+```
$(function() {
var tabContainers = $('div.tabs > div');
tabContainers.hide().filter(':first').show();
@@ -89,6 +89,6 @@ $(window).bind('hashchange', function(){
$(window).trigger("hashchange");
});
-
+```
Once last note: if we trigger the hashchange event, and there’s no hash on the URL, then we need to give it a default. In this case I’ve given it #first as a default so that it always lands on the first tab if there’s nothing pre-selected.
\ No newline at end of file
diff --git a/page/performance/append-outside-loop.md b/page/performance/append-outside-loop.md
index c10874ce..9b357d0f 100644
--- a/page/performance/append-outside-loop.md
+++ b/page/performance/append-outside-loop.md
@@ -7,18 +7,18 @@ tags: performance
Touching the DOM comes at a cost; if you're appending a lot of elements to the
DOM, you will want to append them all at once, rather then one at a time. This is common problem when appending elements within a loop.
-
+```
$.each(myArray, function(i, item) {
var newListItem = '' + item + '';
$('#ballers').append(newListItem);
});
-
+```
One common technique is to leverage a document fragment. During each iteration
of the loop, you append the element to the fragment rather than the DOM
element. After the loop, just append the fragment to the DOM element.
-
+```
var frag = document.createDocumentFragment();
$.each(myArray, function (i, item) {
@@ -29,11 +29,11 @@ $.each(myArray, function (i, item) {
});
$('#ballers')[0].appendChild(frag);
-
+```
Another technique, which is quite simple, is to build up a string during each iteration of the loop. After the loop, just set the html of the DOM element to that string.
-
+```
var myHtml = '';
$.each(myArray, function(i, item) {
@@ -41,6 +41,6 @@ $.each(myArray, function(i, item) {
});
$('#ballers').html(myHtml);
-
+```
There are of course other techniques you could certainly test out; a great way to test the performance of these is through a site called [jsperf](http://jsperf.com). This site allows you to benchmark each technique and visually see how it performs across all the browsers.
diff --git a/page/performance/cache-loop-length.md b/page/performance/cache-loop-length.md
index dbdd8d20..fe6fc813 100644
--- a/page/performance/cache-loop-length.md
+++ b/page/performance/cache-loop-length.md
@@ -6,10 +6,11 @@ tags: performance
In a for loop, don't access the length property of an array every time; cache
it beforehand.
-
+
+```
var myLength = myArray.length;
for (var i = 0; i < myLength; i++) {
// do stuff
}
-
+```
diff --git a/page/performance/clever-conditionals.md b/page/performance/clever-conditionals.md
index 0daf34dc..cbdfd2f1 100644
--- a/page/performance/clever-conditionals.md
+++ b/page/performance/clever-conditionals.md
@@ -3,8 +3,8 @@ title: Clever Conditionals
attribution: jQuery Fundamentals
tags: performance
---
-
+```
// old way
if (type == 'foo' || type == 'bar') { ... }
@@ -13,4 +13,4 @@ if (/^(foo|bar)$/.test(type)) { ... }
// object literal lookup
if (({ foo : 1, bar : 1 })[type]) { ... }
-
+```
\ No newline at end of file
diff --git a/page/performance/detach-elements-before-work-with-them.md b/page/performance/detach-elements-before-work-with-them.md
index b4bf7f6d..ac64a3bf 100644
--- a/page/performance/detach-elements-before-work-with-them.md
+++ b/page/performance/detach-elements-before-work-with-them.md
@@ -8,11 +8,11 @@ The DOM is slow; you want to avoid manipulating it as much as possible. jQuery
introduced `$.fn.detach` in version 1.4 to help address this issue, allowing you
to remove an element from the DOM while you work with it.
-
+```
var $table = $('#myTable');
var $parent = $table.parent();
$table.detach();
// ... add lots and lots of rows to table
$parent.append(table);
-
+```
diff --git a/page/performance/dont-act-on-absent-elements.md b/page/performance/dont-act-on-absent-elements.md
index 64a1c44d..1409c36c 100644
--- a/page/performance/dont-act-on-absent-elements.md
+++ b/page/performance/dont-act-on-absent-elements.md
@@ -8,7 +8,7 @@ jQuery won't tell you if you're trying to run a whole lot of code on an empty
selection — it will proceed as though nothing's wrong. It's up to you to verify
that your selection contains some elements.
-
+```
// BAD: this runs three functions
// before it realizes there's nothing
// in the selection
@@ -27,8 +27,7 @@ jQuery.fn.doOnce = function(func){
$('li.cartitems').doOnce(function(){
// make it ajax! \o/
});
-
-
+```
This guidance is especially applicable for jQuery UI widgets, which have a lot
of overhead even when the selection doesn't contain elements.
diff --git a/page/performance/optimize-selectors.md b/page/performance/optimize-selectors.md
index b41fee9e..a11aa5d7 100644
--- a/page/performance/optimize-selectors.md
+++ b/page/performance/optimize-selectors.md
@@ -12,13 +12,13 @@ jQuery to the browser. However, there are still some tips to keep in mind.
Beginning your selector with an ID is always best.
-
+```
// fast
$('#container div.robotarm');
// super-fast
$('#container').find('div.robotarm');
-
+```
The `$.fn.find` approach is faster because the first selection is handled
without going through the Sizzle selector engine — ID-only selections are
@@ -30,26 +30,26 @@ native to the browser.
Be specific on the right-hand side of your selector, and less specific on the
left.
-
+```
// unoptimized
$('div.data .gonzalez');
// optimized
$('.data td.gonzalez');
-
+```
Use `tag.class` if possible on your right-most selector, and just tag or just
`.class` on the left.
## Avoid excessive specificity.
-
+```
$('.data table.attendees td.gonzalez');
// better: drop the middle if possible
$('.data td.gonzalez');
-
+```
A "flatter" DOM also helps improve selector performance, as the selector engine
has fewer layers to traverse when looking for an element.
@@ -59,11 +59,11 @@ has fewer layers to traverse when looking for an element.
Selections that specify or imply that a match could be found anywhere can be
very slow.
-
+```
$('.buttons > *'); // extremely expensive
$('.buttons').children(); // much better
$('.gender :radio'); // implied universal selection
$('.gender *:radio'); // same thing, explicit now
$('.gender input:radio'); // much better
-
+```
diff --git a/page/performance/read-the-source.md b/page/performance/read-the-source.md
index 97e36eff..0b14e6b6 100644
--- a/page/performance/read-the-source.md
+++ b/page/performance/read-the-source.md
@@ -6,5 +6,5 @@ attribution: jQuery Fundamentals
tags: performance
---
-Use the source as your documentation — bookmark
+Use the source as your documentation. Bookmark
[http://bit.ly/jqsource](http://bit.ly/jqsource) and refer to it often.
diff --git a/page/performance/use-stylesheets-for-changing-css.md b/page/performance/use-stylesheets-for-changing-css.md
index ba0e35aa..a237a001 100644
--- a/page/performance/use-stylesheets-for-changing-css.md
+++ b/page/performance/use-stylesheets-for-changing-css.md
@@ -6,9 +6,9 @@ tags: performance
If you're changing the CSS of more than 20 elements using `$.fn.css`, consider
adding a style tag to the page instead for a nearly 60% increase in speed.
-
+```
// fine for up to 20 elements, slow after that
$('a.swedberg').css('color', '#asd123');
$('')
.appendTo('head');
-
+```
diff --git a/page/performance/variable-definition.md b/page/performance/variable-definition.md
index 2fbaee9d..02fb9d8b 100644
--- a/page/performance/variable-definition.md
+++ b/page/performance/variable-definition.md
@@ -6,7 +6,7 @@ tags: performance
Variables can be defined in one statement instead of several.
-
+```
// old & busted
var test = 1;
var test2 = function() { ... };
@@ -16,10 +16,10 @@ var test3 = test2(test);
var test = 1,
test2 = function() { ... },
test3 = test2(test);
-
+```
In self-executing functions, variable definition can be skipped all together.
-
+```
(function(foo, bar) { ... })(1, 2);
-
+```