It is easy enough to link Javascript to HTML. Javascript links can be added to the document head, or body, or both. With HTML5, Javascript can also be loaded and executed before page load, during page load or after page load, and this is where it gets tricky. In this post I cover Javascript linking, as well as loading and execution practices and where they are suitable.
Linking Javascript to HTML from the HEAD of a document makes sense when you are loading a library of functions that the page uses. For example, you have wired up event handlers on elements that call functions defined in the linked library. This is my default approach to link Javascript to HTML. I like to keep Javascript out the document body and encapsulated in a page specific file that ties into page events to manipulate the DOM or provide functions that can be called by element events.
Here is an example of a script file called 'myscript.js' linked into a document 'head'.
<head>
<script src='myscript.js'/>
</head>
Loading Javascript in the body is when you have some script that needs to run when the page is loaded. I tend to stay away from this approach, however, it can be handy if you only have a few lines of code to run, or you need to manipulate an HTML document in a specific place. The advantage of linking script in the body is when it occurs at the end of a document to optimize the load and execution of the script.
The script 'type' attribute identifies the Internet media type (formerly known as the MIME type) of the script file. In HTML5, this attribute is no longer necessary. You may wish to include it to support pre-HTML5 browsers however. I tend to include it out of habit, but this is a a habit I am getting away from, mainly to keep HTML documents simpler.
File paths always cause me problems. So here is some quick guidance on how browsers use paths to locate script files.
These are the most straightforward. Any page in the site will look at this exact location to load the js file.
The browser expects this file to live in the same folder as the current page.
The browser expects this file in the root of the current web site
The async attribute allows Javascript to execute asynchronously while the page is parsing. If async is not specified, the page load waits until the javascript has been executed. Waiting for large scripts can be a page performance problem.
<head>
<script src='myscript.js' async/>
</head>
Should async be added to every script? Yes, if the page can be displayed before the script has finished.
The async attribute is specific to HTML5 and is a minimized version of the fully specified async='async'
Adding defer to a script element tells the browser to load the script but execute it after the page has been loaded. It used to be common practice to place script tags at the end of HTML documents to achieve this result.
<head>
<script src='myscript.js' defer/>
</head>
While scripts at the end of a document don't execute until the document DOM is loaded, that also aren't loaded either. The 'defer' attribute allows the browser to load the JS file, and defer the execution, instead of deferring the script load and the execution.
Async and Defer are only valid for external scripts. They are ignored if there is no 'src' attribute. Async and Defer are only relevant to script tags specified in the document HEAD. If you use both async and defer together, async will take precedence. I believe specifying both is a mistake because you will get unpredictable results across browsers, depending on what functionality is supported, and your code is confusing as these attributes have different intentions.
Javascript files can be added dynamically to a page (by Javascript).
var script = document.createElement('script');
script.src = 'myscript.js';
document.body.append(script);
By default, dynamic scripts are loaded asynchronously. This can be changed by setting the 'async' attribute on the script element to false.
Dynamically loading scripts at the bottom of an HTML document is the optimal approach for page load because the script is neither loaded nor executed until the page render is complete. This approach is also the most cross browser friendly as it does not rely on the 'asyn' or 'defer' attributes. Remember that javascript that is needed to render the page will need to load earlier. Move this code to a new file and link it in the document head with a 'defer' so that it can act on loaded DOM elements.
Here is some additional information on async and defer.
Some arguments for dynamic loading Javascript.
And, a post I wrote on 7 Free XML validation tools that can be used to validate your HTML documents - check it out.