Introduction
Loading is a crucial topic in the world of web development. Developers are nearly always working to get their websites to load ASAP.
JavaScript with its huge inventory of events doesn't put loading aside. It provides an array of events to operate around different areas of loading and allow the developer to tailor all these areas according to the application's needs.
In this chapter, we'll take a look over four different events under the category of loading and see how can we use them to take the interactivity of our webpages to a whole new level.
The load event
For a given resource-fetching HTML element (such as <link>
, <script>
), the moment it loads completely, it dispatches a load
event.
The load
event is one of the most useful and most handled events in JavaScript. At some point in time, we all do want to run a piece of code when a script has been completelyexecuted, a stylesheet has been completely parsed, an audio file has been downloaded, and so on.
Let's consider a quick example. Say we want to make a log right after the following image is completely downloaded.
<img src="image.png">
To do so, we'll need to work with the onload
handler of the <img>
element.
var img = document.getElementsByTagName("img")[0];
img.onload = function() {
console.log("Image completely loaded");
}
The moment the image is completely downloaded and parsed, its load
event will occur and thereby the onload
handler defined in line 2 will be invoked. This will result in a console log being made.
<img>
tag in the html as shown below:<img src="image.png">
<script> /* code goes here */ </script>
Moving on, the most interesting aspect of the load
event is that it's also available on the whole HTML document i.e the window
object.
This means that we can track when the whole document gets loaded, and consequently execute any piece of code at this point.
However, when we talk about the loading of the whole document, we need to specifically define the meaning of this - does the loading take into account sub-resources such as external scripts, stylesheets, etc.
load
event fires when all of its underlying resources are completely fetched, parsed and executed.In contrast, the load
event for, let's say, a stylesheet fires when the stylesheet itself loads completely - any underlying subresource like a background image isn't considered.
Consider the following HTML:
<!DOCTYPE html>
<html>
<body>
<!-- a resource-fetching tag -->
<img src="image.png">
</body>
</html>
All we have here is an image element and nothing else. Now using this HTML, we shall demonstrate the behavior of the load
event of window
.
Suppose we have the following script right after the <img>
element shown above:
window.onload = function() {
console.log("Everything has been loaded!");
}
And with this also suppose that the image takes a decent amount of time to be loaded; somewhere around 3 seconds.
The log here will be made when the load
event fires on the whole HTML document and this will happen only when all its underlying resources are processed completely. That is, it'll fire when the image element loads completely which takes approximately 3 seconds.
If we had a couple more resource-fetching elements here such as <link>
, <script>
, <audio>
etc, instead of just a single <img>
element, then load
would've fired when all of them finished loading.
Many browsers display a loading spinner while a website is loading uptil the point the load
event is dispatched. And we all know, websites that keep the spinner spinning for long give a not-so-good impression.
Therefore, it's recommended to developers that they construct websites in a way that they load as quickly as possible, and put the spinners to a halt in no time! This requires understanding a couple of topics such as asynchronous loading and lazy loading.
Things to note!
While working with the load
event, one needs to remember a couple more things.
Firstly, the onload
handler on window
is equal to onload
handler on document
. In other words, handling load
on window
or document
is interchangeable.
The following two snippets are, likewise, identical:
window.onload = function() {
console.log("Loaded completely!")
}
document.onload = function() {
console.log("Loaded completely!");
}
Secondly, the load
event doesn't fire on every HTML element - it works only on resource-fetching tags like <link>
, <script>
, <img>
, <iframe>
, <audio>
, <video>
and so on.
Even logically, the following code doesn't make sense:
<p onload="console.log('Paragraph loaded!')">A paragraph</p>
Anyways, a couple of more examples with onload
follow.
Here we call someFunction()
when the stylesheet loads:
<link rel="stylesheet" href="styles.css" onload="someFunction()">
Here we dynamically create a stylesheet in JavaScript and wait for it to load, after which we make a log in the console:
var stylesheet = document.createElement("link");
stylesheet.onload = function() {
console.log("Stylesheet loaded!");
}
stylesheet.rel = "stylesheet";
stylesheet.href = "styles.css";
document.head.appendChild(stylesheet); // append element to make a request for it
Before the load event
It's good to know that load
takes into account all resources of an HTML document before getting fired. However, if one doesn't want to take this deal then what?
Say you want to execute some script as soon as the document itself loads completely - underlying resources may still be in the process of completion.
In these cases, what you need is the DOMContentLoaded
event.
DOMContentLoaded
fires when a webpage's DOM tree is fully constructed.The DOM tree of a webpage finishes constructing when all of its markup is completely parsed and executed. This means that DOMContentLoaded
fires when a webpage is itself parsed fully.
Unlike load
, this event doesn't wait for underlying resources such as images, iframes, audio, video etc - as soon as the HTML is itself loaded, it fires.
Some important things to note about this event are shown as follows:
- Unlike nearly all JavaScript events,
DOMContentLoaded
does NOT have a correspondingonDOMContentLoaded
event property. It can be used with the JavaScript event listener method only i.eaddEventListener()
. - Unlike all event names in JavaScript such as
load
,mousemove
and so on,DOMContentLoaded
doesn't follow lower casing (as you can see from the start of its name). - It only fires on the
document
object. Any other object for example,window
, ordocument.body
isn't a target of this event.
Fulfilling all the conditions given above we arrive at the following code:
document.addEventListener("DOMContentLoaded", function() {
console.log("Content loaded!");
});
Now add this code to the previous example with onload
and notice that it will be logged before onload
since it doesn't need to wait for the loading of any underlying resource.
Following is a showcase of some of the illegal ways to use the event DOMContentLoaded
:
// There is nothing like this
document.onDOMContentLoaded = function() {
console.log("Content loaded!");
}
// or even this
document.DOMContentLoaded = function() {
console.log("Content loaded!");
}
// or even this!
window.addEventListener("DOMContentLoaded", function() {
console.log("Content loaded!");
});
onbeforeunload
onbeforeunload
occurs just before the browser is closed. It can be used, for an example, to ask a confirmation from the user whether he really wants to exit the page or not.
window.onbeforeunload = function(e) {
e.preventDefault(); // cancel default action
e.returnValue = ""; // cancel default action and show a confirm dialog
}
Usually to cancel the default behavior of any event we use the preventDefault()
method on the event object and we can do so with onbeforeunload
too. But the problem with this is that some browsers don't consider the method preventDefault()
inside this event.
Hence for them we need to fallback with the returnValue
property. The property prevents the default action, and shows a confirm dialog to the end user.
Handling errors
It's not surprising to know that when requesting for a resource, there's is a likelihood of something fishy happening on the backend or to the network connection, leading to an error in the response.
Luckily JavaScript has an event for dealing with such cases too - error
.
For a given resource-fetching element, the error
event fires when somehow the underlying resource can't be fetched, because the user's network is disabled, or the server returns a error response, or some other reason.
Below is an instance where this event takes place.
We have an <img>
element refering to an image that just doesn't exist! Likewise the error
event will take over.
<img src="nonExistentImage.png">
var img = document.getElementsByTagName("img")[0];
// Handing the error case for the img
img.onerror = function() {
alert("An error occured!");
}
error
event doesn't work for the HTML document. This is because if the main HTML page fails, then it means that nothing regarding the page is downloaded and likewise nothing is executed!The browser handles document-level failures on its own. The same doesn't apply for HTML documents loaded using AJAX or otherwise, as in iframes.