Tentang Tag Script di Dalam HTML

Aldimhr
JavaScript Indonesia Community
7 min readOct 19, 2021
Tentang Tag Script di Dalam HTML

Tulisan ini saya buat untuk mengulas pertanyaan

  • Bagaimana praktik terbaik dalam mereferensikan / menulis kode JavaScript di dalam HTML?
  • Kenapa umumnya <script> diletakkan di akhir <body> ?

Penulisan Kode JavaScript

Salah satu alasan dipilihnya penulisan kode JavaScript biasanya mempertimbangkan terkait dengan semakin banyaknya kode yang ditulisakan dalam satu file (pengelolaan kode). Terdapat 2 cara yang umum digunakan

Pertama, menuliskan langsung di dalam tag <script> atau disebut dengan metode inline

<script>    // kode JavaScript</script>

Kedua adalah metode external, yaitu menuliskan kode JavaScript pada file terpisah. Sama seperti sebelumnya, menggunakan tag <script> tapi pada kasus ini perlu menambahkan attribute srcyang mereferensikan nama dari file JavaScript yang ingin dimuat, sehingga akan terlihat seperti ini:

<script src="file.js"></script>

Penempatan <script>

Salah satu alasan dipilihnya penempatan <script>biasanya mempertimbangkan terkait dengan urutan dimuat ketika halaman akan ditampilkan.

Terdapat 2 cara yang umum digunakan yaitu diletakkan di dalam tag<head> dan di akhir tag<body>

<html>
<head>
// JavaScript di dalam <head>
<script src="file.js"></script>
</head>
<body>
<div id="dom"></div>
// JavaScript di akhir <body>
<script src="file.js"><script>
</body>
</html>

Proses Parsing HTML

Faktanya, mengelola file JavaScript di browser cukup rumit, karena eksekusi kode memblokir proses lain pada browser, seperti UI painting. Setiap kali <script> ditemukan, halaman harus berhenti dan menunggu kode untuk diunduh (jika eksternal) dan dijalankan sebelum melanjutkan untuk memproses sisa halaman.

Hal tersebut dikarenakan sebagian besar browser menggunakan satu proses untuk pembaruan User Interface (UI) dan eksekusi JavaScript, jadi pada waktu yang sama hanya terjadi satu proses saja.

Contoh:

<html>
<head>
<title>Script Example</title>
</head>
<body>
<p>
<script>
document.write("The date is " + (new Date()).toDateString());
</script>

</p>
</body>
</html>

Ketika browser mulai membaca satu persatu kode HTML dan menemukan <script> (seperti pada kode diatas) maka browser akan menunggu untuk melihat perilaku dari kode JavaScript yang disematkan.

Tanpa menunggu, browser tidak tahu apakah kode tersebut menambahkan konten, menambahkan elemen lain, atau bahkan menutup tag.

Setelah browser tahu perilaku dari kode tersebut, maka browser akan melanjutkan untuk me-parsing dan me-render halaman.

Hal yang sama terjadi untuk JavaScript yang dimuat dengan attribute src , browser harus terlebih dahulu mengunduh kode dari file eksternal, lalu me-parsing dan mengeksekusi kode.

Render halaman dan interaksi pengguna sepenuhnya di blokir selama waktu tersebut

Contoh lain:

<html> 
<head>
<title>Document</title>
<script src="file1.js"></script>
<script src="file2.js"></script>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<p>Hello World!</p>
</body>
</html>

Browser tidak akan merender apapun di halaman hingga menemui pembuka tag <body>

Menempatkan script di dalam tag <head> biasanya memperlihatkan proses yang cukup lambat, seringkali halaman hanya berwarna putih untuk beberapa saat, bahkan sebelum user dapat mulai membaca atau berinteraksi dengan halaman.

Eksekusi kode JavaScript memblokir unduhan file lainnya

Pada diagram waterfall diatas, file JavaScript pertama mulai diunduh dan memblokir file lain mana pun, untuk sementara.

Selanjutnya, terdapat penundaan ketika file1.js selesai diunduh dan ketika file2.js mulai diunduh. Ruang kosong tersebut merupakan waktu yang dibutuhkan kode yang berada di file1.js untuk dieksekusi sepenuhnya.

Setiap file harus menunggu hingga file sebelumnya telah diunduh dan dieksekusi, sebelum unduhan berikutnya dapat dimulai. Sementara itu, user akan melihat layar putih kosong karena file sedang diunduh satu per satu.

Masalah Penempatan

Sebelumnya, kita sudah mengetahui bahwa script dapat diletakkan pada head atau body

<html>
<head>
<script>
// document.head is available
// document.body is not!
</script>

</head>
<body>
<script>
// document.head is available
// document.body is available
</script>

</body>
</html>

Pada kode diatas kita melihat terdapat masalah dengan penempatan. Ketika kode JavaScript diletakkan di head , kode tersebut tidak dapat mengakses body , ini merupakan masalah serius jika kode tersebut memiliki fungsi untuk mengelola element di dalam body .

Seperti yang sudah dibahas sebelumnya, hal ini terjadi karena browser akan membaca satu persatu element HTML dari atas ke bawah, sehingga ketika script di dalam head dimuat, browser belum merender apapun element HTML di dalam tag <body> .

Solusi umum yang digunakan adalah meletakkan script di akhir body

<html>
<head>
</head>
<body>
// ...
// ...
<script>
// kode ...
</script>
<script src="file.js"></script>

</body>
</html>

Hal ini dilakukan agar browser memuat element HTML di dalam bodydahulu dan memuat script diakhir. Sampai titik ini kita dapat melihat bahwa solusi ini cukup menyelesaikan masalah sebelumnya.

Dengan solusi ini browser akan memperhatikan script dan mulai mengunduhnya hanya setelah mengunduh documen HTML secara lengkap.

Namun, hal ini dapat sedikit menimbulkan masalah untuk document HTML yang sangat panjang, hal tersebut dapat menyebabkan delay yang cukup lama.

Hal ini sebenarnya tidak akan terlihat jika koneksi internet sangat cepat, namun banyak orang yang masih memiliki kecepatan internet yang lambat dan menggunakan koneksi internet seluler yang jauh dari sempurna.

Defer

Sejak HTML 4, attribute baru untuk <script> ditambahkan, yaitu defer . Attribute defer digunakan untuk memberitahu browser agar tidak menunggu script .

Browser akan terus memproses HTML, membangun DOM. script dimuat di ‘background’, kemudian berjalan saat DOM sepenuhnya selesai dibuat.

script dengan attributedefer dapat diletakkan dimana saja di dalam HTML, namun defer tidak berfungsi dengan baik jika kode Javascript dituliskan inline atau internal

// defer berfungsi ketika menggunakan eksternal file
<script defer src="file.js"> </script>
// defer tidak berfungsi ketika dituliskan inline
<script defer>
// Kode..
</script>

script dengan defer selalu dijalankan saat DOM sudah sepenuhnya dimuat, tapi sebelum event DOMContentLoaded

<p> ... </p><script>
document.addEventListener('DOMContentLoaded', () =>
alert("DOM siap setelah defer")
);
</script>
<script defer src"file.js"></script>

script dengan attributedefer akan dijalankan sesuai dengan urutannya, sama dengan script biasa.

<script defer src"file1.js"></script>
<script defer src"file2.js"></script>
<script defer src"file3.js"></script>

Browser akan memindai halaman untuk mencari scriptdan mengunduhnya secara paralel. Jadi pada contoh diatas, ketiga script diunduh secara paralel, hal ini memungkinkan file2.js atau file3.js selesai pertama kali sebelum file1.js

Namun, selain memberi tahu browser untuk tidak memblokir, attribute defer juga memastikan bahwa urutan relatif tetap terjaga.

Jadi, meskipun file2.js atau file3.js dimuat terlebih dahulu, browser akan menunggu dan menjalankannya sesuai urutan pada contoh kode diatas.

Async

Attribute async hampir sama dengan defer . asyncjuga memiliki fungsi agar script tidak memblokir proses lain, perbedaan mendasarnya adalah perilaku dari kedua attribute tersebut.

defer akan diunduh secara paralel, tapi pada akhirnya akan dimuat sesuai dengan urutan kode, dari atas ke bawah. Sedangkanasync tidak, async akan mengunduh dan memuat secara paralel, jadi async cocok digunakan ketika satu script dengan yang lain tidak memiliki ketergantungan (independen).

Selain itu, DOMContentLoaded dan async tidak saling menunggu, artinya keduanya tidak dapat dipastikan mana yang akan dimuat terlebih dahulu.

Browser Compatibility

Penting untuk mengetahui apakah async dan defer sudah didukung sepenuhnya oleh browser.

https://caniuse.com/?search=defer
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script

Dari gambar diatas, bisa kita lihat async dan defer hampir didukung secara penuh oleh kebanyakan browser saat ini, kecuali Opera Mini.

Kembali ke pertanyaan

  • Manakah cara yang baik untuk menuliskan / mereferensikan kode JavaScript di HTML?

— Menggunakan script di akhir body jika user yang ditargetkan memiliki koneksi internet yang baik.

— Menggunakan defer jika file satu dan file lain memiliki ketergantungan sehingga dimuat secara berurut merupakan kebutuhan.

— Menggunakan async jika file satu dan file lain tidak memiliki ketergantungan (independen)

—Menggunakan eventDOMContentLoaded jika kode JavaScript di tuliskan secara inline dan berada di dalam <head> , agar dimuat setelah DOM tersedia.

  • Kenapa umumnya <script> diletakkan di akhir <body> ?

Asumsi saya, hal ini dilakukan karena sebelumnya async dan defer belum berjalan dengan baik di semua browser, agar script dimuat setelah DOM di muat terlebih dahulu.

Dengan mengetahui hal di atas, jika menggunakan defer , async ataupun event DOMContentLoaded bukan tidak mungkin kita meletakkan script di dalam head bukan?

<html>
<head>
<script defer src="file1.js"></script>
<script async src="file2.js"></script>
<script>
document.addEventListener('DOMContentLoaded', () => {
// kode..
});
</script>
</head>
<body>
...
...
</body>
</html>

Catatan

Dengan menggunakan defer atau async , memungkinkan user akan melihat halaman sebelum script dimuat.

Pada beberapa kasus, tidak akan menampilkan beberapa komponen grafis sebelum JavaScript diinisiasi.

Dengan begitu, menampilkan animasi atau apapun itu yang menunjukkan bahwa halaman sedang loading, penting ditambahkan agar user melihat dengan jelas apa yang dilakukan oleh halaman, dan apa yang masih dipersiapkan.

async dan defer memiliki sifatnya masing masing, jika diilustrasikan dengan bagan, akan tampak seperti ini

https://html.spec.whatwg.org/#the-script-element

Tentu masih ada cara lain untuk menambahkan kode JavaScript di HTML, yang mungkin akan dibahas pada artikel lain.

--

--