Interactive Development Best Practices
Documenting best practices for interactive development is an exhaustive task, and is one that, if done effectively, would fill the pages of several books. The purpose of this guide is not to provide an all-encompassing list of best practices, but to highlight many of the most important components of a stable, high performance web page.
JavaScript
-
Restrict JavaScript to External Files
Avoiding inline JavaScript is even more critical than avoiding inline CSS. Including code within
<script>
elements is sometimes permissible for certain rare use cases, but keep in mind that this has a negative impact on SEO, and increases the filesize of the HTML without the benefit of caching or compression.JavaScript event attributes (such as
onclick
oronload
) and JavaScript included within thehref
attribute of an anchor tag should never be used.A full discussion of this topic can be found here.
It should be noted that HTML comments within
<script>
elements are no longer necessary. None of the browsers that required this hack are still in use. Similarly, thetype
attribute and the practice of enclosing JavaScript within a CDATA section, required in HTML4 and XHTML, are no longer necessary in HTML5. -
Placement of External JavaScript Files
JavaScript downloads are said to be blocking, because nothing after the JavaScript include in the HTML can be parsed until the JavaScript has finished downloading and executing. This can have a huge impact on the performance of a web page, and there are a couple of common ways of dealing with it.
Include JavaScript near the end of the page
The most common method of dealing with JavaScript blocking is to include JavaScript at the end of your HTML document, just prior to the closing
</body>
tag. This also helps to ensure that the DOM elements of the page have already been loaded prior to JavaScript execution (so technically, you can omit event handlers that watch for the page to be loaded or for the DOM to be ready when including scripts in this fashion).If there is code that needs to execute prior to DOM elements being rendered (such as code that modifies the
class
attribute of thehtml
element, it may still be loaded in thehead
of the document.When including JavaScript with
<script>
elements at the bottom of the page, it is important to minimize the number of different JavaScript files being loaded. This becomes less important when using a script loader.Use a JavaScript loader
A recent trend in the web development world is to load JavaScript files asynchronously. The
async
anddefer
attributes (described here) are meant to provide this functionality, but there are issues with both that prevent them from being a total solution.Until such a time as browsers can provide asynchronous loading and dependency management natively (expect this with ES Harmony), it is necessary to use a script loader. A good script loader can end up being the only JavaScript that you include in the traditional fashion, with all other files being called in through the loader's API. For an approach that combines the benefits of a script loader with the built-in advantages of
async
anddefer
, check out this article.Script loaders provide many benefits; they can:
-
Load scripts like images, which load separately from the page rendering process (i.e., are non-blocking)
-
Provide dependency management, so that scripts can be loaded in parallel, but executed in order (huge performance gains here)
-
Provide callback functions to script loads, ready functions that can execute on a script-by-script basis, and much more
A comparison of some of the more popular script loaders can be found in this Google spreadsheet. Note that this spreadsheet is no longer maintained.
This page uses curl.js to load JavaScript in the fastest way possible (and even allows us to load scripts in the
<head>
of the document). One advantage to curl.js is that it follows the CommonJS AMD (asynchronous module definition) specification. This increases the portability of application code and ensures a consistent interface that even translates well into the realm of the server (with Node.js). -
-
Use jQuery
In depth knowledge of the JavaScript language and the ability to perform common tasks without a JavaScript library is strongly encouraged. That said, it isn't realistic or efficient to start from scratch for every project, and JavaScript libraries are invaluable for their ability to simplify common functionality, like DOM manipulation and AJAX requests.
There is no such thing as a "best" JavaScript library, but given that jQuery is currently the most popular, it is recommended for use in new web pages and applications. This increases the likelihood that other developers will be comfortable working with the code that you write.
If there is already a different JavaScript framework in place for your project (Mootools, Dojo, YUI3, etc), you should make every effort to work within the API provided by that framework and do not include jQuery or another such library unless it is absolutely necessary to complete your work. Libraries are very similar in terms of the types of functionality they offer, and they are very large in file size. Including more than one is a wasteful use of your users' bandwidth.
When including jQuery (or another library), you may want to consider linking to a file on a content delivery network, like the one provided by Google: http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js. Using a CDN provides a number of benefits: the file usually originates from a server near to the user geographically, will download concurrently with other scripts (because it's coming from a different domain), and often benefits from caching, since multiple web sites all point to the same URI.
-
Organize Your Code
Putting thought into the structure and organization of your JavaScript enables you to write code that is easier to maintain, more reusable, easier to read, and less likely to cause collisions with other scripts. There are almost as many ways to effectively organize code as there are developers, but several tried and true patterns have emerged over the years:
-
Object literal (basically, the singleton pattern at its simplest)
-
Inheritance patterns encourage code reuse and organization; there are several different ways of accomplishing inheritance in JavaScript, but developers are encouraged to use one of the following:
-
JavaScript is a class-free, prototypal language, but it has sufficient expressive power to simulate a classical system; Pseudo-classical inheritance can be a useful pattern to follow for developers who are familiar with conventional object-oriented languages like C++ and Java
-
Prototypal inheritance better lends itself to the features of the JavaScript language, and is more memory efficient in some situations; Prototypal inheritance is a little strange, and may be difficult to get used to if you're used to a conventional object-oriented language
An example prototypal inheritance implementation with some helpful utility functions can be found here; Note that two of the utility functions are ES5 polyfills, which are intended to provide ECMAScript 5 functionality in ECMAScript 3 browsers
-
-
General Coding Practices
-
Use a code quality tool like JSLint; JSLint is also integrated into some code authoring tools, such as the Aptana IDE
-
Don't use
document.write()
-
Comment your code thoroughly; the use of a standardized documentation format (such as YUI Doc, ScriptDoc, or Natural Docs) is recommended
-
Declare variables at the top of their containing function
-
Don't use reserved words for variables, functions, or object property names
-
Always use
var
statements when declaring variables, and never use thevar
statement when assigning to a variable that has previously been declared -
When commenting out code rather than providing documentation, favor single line comments over multi-line comments; Some regular expressions may inadvertently end a multi-line comment, so single line comments are safer
-
Strive to create functions which can be generalized, take parameters, and return values; This allows for substantial code reuse and, when combined with includes or external scripts, can reduce the overhead when scripts need to change
For example, instead of hard coding a pop-window with window size, options, and url, consider creating a function which takes size, url, and options as variables
- Minimize the use of global variables (see Organize Your Code, above)
-