Dua chapter terakhir menaruh script di akhir body tanpa menjelaskan mengapa posisi itu dipilih. Jawabannya ada pada cara browser mengurai HTML: parser membaca dokumen dari atas ke bawah, dan elemen script dapat mengubah ritme kerjanya. Pada chapter ini kita membedah tiga mode pemuatan script — classic, defer, dan async — beserta type="module" yang mengikuti aturan defer, lalu membuktikan perbedaannya lewat satu file demo.

Script Classic Menghentikan Parser #

Browser mengurai HTML memakai komponen bernama parser. Ketika parser tiba pada elemen script tanpa atribut tambahan — script classic — parser berhenti: file diunduh (bila eksternal), kode dieksekusi sampai tuntas, lalu parsing dilanjutkan.

Perilaku ini adalah warisan desain era awal web: script classic boleh mengubah isi dokumen saat parsing berlangsung, sehingga browser tidak berani melanjutkan sebelum kode selesai. Konsekuensinya nyata — file script besar atau jaringan lambat membuat konten di bawahnya menunggu lebih lama.

defer: Unduh Paralel, Eksekusi Setelah Parsing #

Atribut defer mengubah ritme menjadi dua tahap yang santai. Pengunduhan berjalan paralel dengan parsing, sehingga parser tidak menunggu. Eksekusi kode, bagaimanapun, menunggu sampai dokumen selesai diurai. Antara beberapa script defer, urutan eksekusi terjaga sesuai urutan tag di dokumen. Kombinasi ini ideal untuk script yang menyentuh elemen halaman: saat kode berjalan, seluruh DOM telah terbentuk, dan tag script tetap boleh di head.

async: Eksekusi Saat Unduhan Selesai #

Atribut async juga mengunduh file secara paralel, tetapi eksekusinya tidak menunggu parsing selesai. Begitu unduhan tuntas, kode langsung dieksekusi — mungkin sebelum parser mencapai akhir dokumen. Karena setiap script async berpacu secara mandiri, urutan eksekusi antar script async tidak dijamin. Mode ini cocok untuk script yang berdiri sendiri dan tidak bergantung pada script lain maupun struktur halaman, misalnya script pihak ketiga untuk penghitung kunjungan.

Modul Berperilaku seperti defer #

Script yang dimuat dengan type="module" tanpa atribut async dieksekusi setelah parsing selesai — aturannya sama seperti defer. Menambahkan atribut defer pada module tidak berpengaruh, karena perilaku itu telah menjadi bawaannya.

Perbandingan dan Kapan Dipakai #

Tabel berikut merangkum ketiga mode classic ditambah module:

ModePengunduhanWaktu eksekusiUrutan terjaga
classicBerurutan, menghentikan parserSaat parser tiba di tagYa
deferParalel dengan parsingSetelah parsing selesaiYa, sesuai urutan tag
asyncParalel dengan parsingBegitu unduhan selesaiTidak dijamin
moduleParalel dengan parsingSetelah parsing selesaiYa

Panduan singkat memilih mode:

  • Script utama yang merujuk elemen halaman → defer.
  • Script pihak ketiga yang berdiri sendiri → async.
  • File .js skema module pada proyek modern → type="module".
  • Script sepele yang harus dieksekusi di posisinya → classic di akhir body.

Contoh: Tiga Mode dalam Satu Halaman #

Demo berikut memuat tiga script sekaligus: satu async di head, satu defer di head, dan satu classic inline di akhir body. Setiap script menambah satu baris catatan pada elemen pre. Kemampuan memilih elemen dan mengubah teks di sini baru dibedah pada dua chapter berikutnya; yang perlu diamati hanyalah urutan barisnya.

<!doctype html>
<html lang="id">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Demo Urutan Eksekusi Script</title>
  <script src="eksekusi-async.js" async></script>
  <script src="eksekusi-defer.js" defer></script>
</head>
<body>
  <h1>Demo Urutan Eksekusi Script</h1>
  <p>Setiap script menambah satu baris pada catatan berikut.</p>
  <pre id="urutan"></pre>
  <script>
    const catatan = document.getElementById("urutan");
    catatan.textContent += "classic: parser berhenti, baris ini dieksekusi langsung\n";
  </script>
</body>
</html>
javascript eksekusi-async.js
// Script async: unduh paralel, eksekusi begitu unduhan selesai
const catatan = document.getElementById("urutan");
catatan.textContent += "async: eksekusi saat unduhan selesai (urutan bebas)\n";
javascript eksekusi-defer.js
// Script defer: unduh paralel, eksekusi setelah parsing selesai
const catatan = document.getElementById("urutan");
catatan.textContent += "defer: eksekusi setelah parser selesai, urutan terjaga\n";

Output yang Dihasilkan:

text
Elemen pre menampilkan tiga baris, contohnya:
  async: eksekusi saat unduhan selesai (urutan bebas)
  classic: parser berhenti, baris ini dieksekusi langsung
  defer: eksekusi setelah parser selesai, urutan terjaga

Baris async dapat muncul di posisi lain pada tiap percobaan,
sedangkan classic selalu tepat di posisinya dan defer selalu
setelah parsing selesai.

Mari kita telaah peran setiap baris penting di atas:

  1. Baris 7 HTML (<script src="eksekusi-async.js" async>): file diunduh sejak awal parsing dan dieksekusi begitu siap.
  2. Baris 8 HTML (<script src="eksekusi-defer.js" defer>): file diunduh paralel, tetapi eksekusinya menunggu dokumen selesai diurai.
  3. Baris 13 HTML (<pre id="urutan">): wadah catatan; elemen pre mempertahankan baris baru sehingga tiap entri tampil pada barisnya sendiri.
  4. Baris 14-17 HTML (script classic inline): dieksekusi tepat saat parser tiba di akhir body, sebelum parsing resmi berakhir.
  5. Baris 3 pada kedua file JS (textContent += ...): setiap script menambah satu baris pada catatan yang sama, sehingga isi pre mencerminkan urutan eksekusinya.

Tiga mode di atas kini menjelaskan mengapa contoh-contoh sebelumnya menaruh script di akhir body: tanpa defer, posisi itulah yang menjamin elemen telah ada saat kode berjalan. Chapter berikutnya masuk ke isi script, dimulai dari keterampilan paling mendasar: memilih elemen DOM.

Referensi resmi untuk pendalaman:

Berkas Sumber

Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.

demo-eksekusi.html

Unduh berkas
html
<!doctype html>
<html lang="id">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Demo Urutan Eksekusi Script</title>
  <script src="eksekusi-async.js" async></script>
  <script src="eksekusi-defer.js" defer></script>
</head>
<body>
  <h1>Demo Urutan Eksekusi Script</h1>
  <p>Setiap script menambah satu baris pada catatan berikut.</p>
  <pre id="urutan"></pre>
  <script>
    const catatan = document.getElementById("urutan");
    catatan.textContent += "classic: parser berhenti, baris ini dieksekusi langsung\n";
  </script>
</body>
</html>

eksekusi-async.js

Unduh berkas
javascript
// Script async: unduh paralel, eksekusi begitu unduhan selesai
const catatan = document.getElementById("urutan");
catatan.textContent += "async: eksekusi saat unduhan selesai (urutan bebas)\n";

eksekusi-defer.js

Unduh berkas
javascript
// Script defer: unduh paralel, eksekusi setelah parsing selesai
const catatan = document.getElementById("urutan");
catatan.textContent += "defer: eksekusi setelah parser selesai, urutan terjaga\n";