The DOM and External Resource Loading

One of the important aspects of working with HTML is understanding that an HTML page is more than just the HTML. It also involves a collection of resources that are external to the HTML document, but displayed or utilized by the document. These include elements like <link>, <script>, <video>, <img>, and <source> with src or href attributes set.

As the DOM tree is parsed and loaded and these external resources are encountered, the browser requests those resources as well. Modern browsers typically make these requests in parallel for faster loading times.

Once the HTML document has been completely parsed, the window triggers the DOMContentLoaded event. This means the HTML document has been completely parsed and added to the DOM tree. However, the external resources may not have all been loaded at this point.

Once those resources are loaded, a separate Load event is triggered, also on the window.

Thus, if you have JavaScript that should only be invoked after the page has fully loaded, you can place it inside an event listener tied to the load event, i.e.:

window.addEventListener('load', function(event) {
    // TODO: Add your code here ...
});

Or, if you want it invoked after the DOM is fully parsed, but external resources may still be loading:

window.addEventListener('DOMContentLoaded', function(event) {
    // TODO: Add your code here ...
});

The former - waiting for all resources to load - tends to be the most common. The reason is simple, if you are loading multiple JavaScript files, i.e. a couple of libraries and your own custom code, using the 'load' event ensures they have all loaded before you start executing your logic.

Consider the popular JQuery library, which provides shorthand methods for querying and modifying the DOM. It provides a JQuery() function that is also aliased to the $. The JQuery code to show a popup element might be:

$('#popup').show();

But if the JQuery library isn’t loaded yet, the $ is not defined, and this logic will crash the JavaScript interpreter. Any remaining JavaScript will be ignored, and your page won’t work as expected. But re-writing that to trigger after all resources have loaded, i.e.:

window.addEventListener('load', function(event) {
    // This code only is executed once all resources have been loaded
    $('#popup').show();
});

Ensures the JQuery library is available before your code is run.

Info

JavaScript is an extremely flexible language that has evolved over time. One side effect of this evolution is that there are often multiple ways to express the same idea. For example, listening for the window’s 'load' event can be written many different ways:

// Using the onload property
window.onload = function(event) {...}

// Using onload property and lambda syntax 
window.onload = (event) => {...}

// Using the addEventListener and lambda syntax
window.addEventListener('load', (event) => {
    ...
});

// Using the JQuery library 
JQuery(function(){...});

// Using the JQuery library with lambda syntax 
JQuery(() => {...});

// Using the JQuery library with $ alias
$(function(){...});

You are free to use whichever approach you like, but need to be able to interpret other programmers' code when they use a different approach.

Loading Resources after the DOM is loaded

There are really two ways to load resources into an HTML page from your JavaScript code. One is indirect, and the other direct. The indirect method simply involves creating DOM elements linked to an outside resource, i.e.:

var image = document.createElement('img');
image.src = 'smile.png';
document.body.appendChild(img);

In this case, when the new <img> element has its src attribute set, the image is requested by the browser. Attaching it to the DOM will result in the image being displayed once it loads.

If we want to know when the image is loaded, we can use the load event:

var image = document.createElement('img');
image.addEventListener('load', function(event){
    console.log('loaded image');
});
image.src = 'smile.png';

Notice too that we add the event listener before we set the src attribute. If we did it the other way around, the resource may already be loaded before the listener takes effect - and it would never be invoked!

However, this approach can be cumbersome, and limits us to what resources can be bound to HTML elements. For more flexibility, we need to make the request directly, using AJAX. We’ll take a look at doing so after we cover HTTP in more depth.