JavaScript Course 8: DOM and Browser
References
Definitions
- The
DOM (Document Object Model) API
allows you to manipulate HTML and CSS, creating, removing and changing HTML, dynamically applying new styles to your page, etc. Every time you see a popup window appear on a page, or some new content displayed (as we saw above in our simple demo) for example, that's the DOM in action. - The
Geolocation API
retrieves geographical information. This is how Google Maps is able to find your location and plot it on a map. - The
Canvas
andWebGL (Web Graphics Library)
APIs allow you to create animated 2D and 3D graphics. People are doing some amazing things using these web technologies – see Chrome Experiments and webglsamples. Audio and Video APIs
likeHTMLMediaElement
andWebRTC (Web Real-Time Communication)
allow you to do really interesting things with multimedia, such as play audio and video right in a web page, or grab video from your web camera and display it on someone else's computer…
Internal JavaScript
<script>
document.addEventListener('DOMContentLoaded', () => {
function createParagraph() {
const para = document.createElement('p');
para.textContent = 'You clicked the button!';
document.body.appendChild(para);
}
const buttons = document.querySelectorAll('button');
for (const button of buttons) {
button.addEventListener('click', createParagraph);
}
});
</script>
External JavaScript
<script src="script.js" defer></script>
script.js
function createParagraph() {
const para = document.createElement('p');
para.textContent = 'You clicked the button!';
document.body.appendChild(para);
}
const buttons = document.querySelectorAll('button');
for (const button of buttons) {
button.addEventListener('click', createParagraph);
}
Inline JavaScript handlers
<button onclick="createParagraph()">Click me!</button>
<script>
function createParagraph() {
const para = document.createElement('p');
para.textContent = 'You clicked the button!';
document.body.appendChild(para);
}
</script>
Please don't do this, however. It is bad practice to pollute your HTML with JavaScript, and it is inefficient — you'd have to include the onclick="createParagraph()"
attribute on every button you want the JavaScript to apply to.
Using addEventListener instead
<button onclick="createParagraph()">Click me!</button>
<script src="script.js"></script>
script.js
const buttons = document.querySelectorAll('button');
for (const button of buttons) {
button.addEventListener('click', createParagraph);
}
Script loading strategies
There are a number of issues involved with getting scripts to load at the right time. Nothing is as simple as it seems! A common problem is that all the HTML on a page is loaded in the order in which it appears.
In the internal example, you can see this structure around the code:
<head>
<script>
document.addEventListener('DOMContentLoaded', () => {
...
});
</script>
</head>
<body>
<!-- ... -->
</body>
In the external example, we use a more modern JavaScript feature to solve the problem, the defer
attribute, which tells the browser to continue downloading the HTML content once the <script>
tag element has been reached.
<script src="script.js" defer></script>
Note: In the external case, we did not need to use the DOMContentLoaded
event because the defer
attribute solved the problem for us. We didn't use the defer
solution for the internal JavaScript example because defer
only works for external scripts.
async
and defer
There are actually two modern features we can use to bypass the problem of the blocking script – async
and defer
(which we saw above). Let's look at the difference between these two.
Scripts loaded using the async
attribute will download the script without blocking the page while the script is being fetched. However, once the download is complete, the script will execute, which blocks the page from rendering. You get no guarantee that scripts will run in any specific order. It is best to use async
when the scripts in the page run independently from each other and depend on no other script on the page.
Scripts loaded with the defer
attribute will load in the order they appear on the page. They won't run until the page content has all loaded, which is useful if your scripts depend on the DOM being in place (e.g. they modify one or more elements on the page).
Here is a visual representation of the different script loading methods and what that means for your page – Figure 1.
To summarize:
async
anddefer
both instruct the browser to download the script(s) in a separate thread, while the rest of the page (the DOM, etc.) is downloading, so the page loading is not blocked during the fetch process.- scripts with an
async
attribute will execute as soon as the download is complete. This blocks the page and does not guarantee any specific execution order. - scripts with a
defer
attribute will load in the order they are in and will only execute once everything has finished loading. - If your scripts should be run immediately and they don't have any dependencies, then use
async
. - If your scripts need to wait for parsing and depend on other scripts and/or the DOM being in place, load them using
defer
and put their corresponding<script>
elements in the order you want the browser to execute them.