This episode breaks down the script element: inline and external scripts, render-blocking execution order, the defer and async attributes, and modules that run later yet more safely.

HTML structures content, CSS decorates it, and JavaScript gives it behavior. Episode 14 covers including JavaScript with script, defer, and async — the best ways to attach scripts to a page so it stays fast.
The position and attributes of script determine when JavaScript executes and whether it blocks rendering. A common mistake — placing a large script in head without defer — makes a page feel slow even though the markup is small.
JavaScript is included in two ways. Inline:
<script>
console.log("Halaman dimuat");
</script>External, using the src attribute:
<script src="js/app.js"></script>External scripts are better for reusable code: they're cacheable, separated from markup, and easier to maintain. An HTML page with long JavaScript inside quickly becomes unreadable.
The classic rule: place script at the end of body, after the content. When the script runs, the whole DOM is already available:
<body>
<h1>Judul</h1>
<p>Konten.</p>
<script src="js/app.js"></script>
</body>When the browser meets a script without special attributes, it stops parsing HTML, downloads and executes the script, then continues. As a result, content below the script appears delayed. The bigger the script, the slower the page feels.
<head>
<script src="js/besar.js"></script>
</head>The body content waits for besar.js to finish before rendering — bad for pages whose content matters above the fold.
defer tells the browser to download the script while still parsing the document, then execute it after parsing finishes, before the DOMContentLoaded event:
<head>
<script defer src="js/app.js"></script>
</head>With defer, the script position no longer matters — it's safe in head and still executes after the document is fully parsed. defer scripts execute in the order they appear.
async downloads the script without blocking parsing and executes it as soon as the download completes — without waiting for the document and without a defined order:
<head>
<script async src="js/analitik.js"></script>
</head>async suits standalone scripts that don't depend on the DOM or other scripts — for example analytics or ad scripts. Scripts that need the DOM aren't safe with async.
body.defer: a main application script that needs the full DOM.async: independent scripts that don't depend on others.The type="module" attribute makes a script treated as an ECMAScript module. Module scripts are automatically defer, run in strict mode, and can use import and export:
<script type="module" src="js/main.js"></script>Because they're automatically defer, modules don't block parsing. Use type="module" for modern JavaScript applications; async can also be combined for independent modules.
Create a page with an external script using defer:
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Tombol Sapa</title>
<script defer src="js/sapa.js"></script>
</head>
<body>
<h1>Tombol Sapa</h1>
<p id="pesan"></p>
<button type="button" id="tombol">Sapa Saya</button>
</body>
</html>Fill in js/sapa.js:
const tombol = document.getElementById("tombol");
const pesan = document.getElementById("pesan");
tombol.addEventListener("click", () => {
pesan.textContent = "Halo, terima kasih sudah menekan tombol!";
});Run the local server with python3 -m http.server 8080, open the page, and click the button. Because of defer, js/sapa.js executes after the entire DOM is ready — getElementById is guaranteed to find its elements.
This is a common cause of pages feeling slow. Put it at the end of body or add defer.
async executes without any guarantee the DOM is ready. For scripts that access elements, use defer or DOMContentLoaded.
Episode 14 gives behavior to your pages: inline and external script, placement at the end of body, defer for execution after parsing, async for independent scripts, and type="module" for modern applications.
Key takeaways:
body.defer executes after the document is fully parsed, in order.async executes as soon as the download finishes, without order.defer; independent scripts use async.type="module" is automatically defer and supports import.In the next episode, episode 15, we'll cover modern interactive elements — details and summary for JavaScript-free accordions, and dialog for accessible modals.