Topics in this subject
JavaScript 1 min read Updated 4 Aug 2026

Part 2 — Loading & Running

Script loading: defer vs async vs module 🎯, runtimes, the console snapshot trap

Script loading — know this table 🎯#

<script src="app.js"></script>                <!-- blocks HTML parsing -->
<script defer src="app.js"></script>          <!-- parallel download, run after parse, in order -->
<script async src="app.js"></script>          <!-- parallel download, run ASAP, no order -->
<script type="module" src="app.js"></script>  <!-- deferred by default, strict, own scope -->
Attribute Downloads Executes Order kept?
(none) immediately, blocks parsing immediately yes
defer in parallel after HTML parsed, before DOMContentLoaded yes
async in parallel as soon as downloaded (may interrupt parse) no
type="module" deferred after parse yes

🟢 Prefer defer or modules — the script sees a fully-built DOM without blocking render. async suits independent scripts (analytics) where order doesn't matter.

Runtimes#

Same engine, different host APIs:

  • Browser — DOM, fetch, timers, Web APIs.
  • Nodefs, http, streams, process. Switch to ESM with "type": "module" in package.json (or .mjs).
  • Deno / Bun — modern runtimes: TypeScript out of the box, fast, batteries included.

The console snapshot trap ⚠️#

console.log(obj);                   // some browsers render obj as it is when you EXPAND it,
                                    // not when you logged it → confusing during mutation
console.log(structuredClone(obj));  // 🟢 snapshot the value at log time