Menambahkan Interaktivitas dengan JavaScript

Dipublikasikan: 31 Desember 2013

JavaScript memungkinkan kita untuk memodifikasi hampir semua aspek halaman: konten, penataan gaya, dan responsnya terhadap interaksi pengguna. Namun, JavaScript juga dapat memblokir konstruksi DOM dan menunda waktu laman dirender. Untuk menghasilkan kinerja yang optimal, jadikan JavaScript Anda asinkron dan tiadakan setiap JavaScript yang tidak penting dari jalur rendering penting.

Ringkasan

  • JavaScript dapat melakukan kueri dan memodifikasi DOM dan CSSOM.
  • Eksekusi JavaScript akan memblokir di CSSOM.
  • JavaScript memblokir konstruksi DOM kecuali secara eksplisit dideklarasikan sebagai asinkron.

JavaScript adalah bahasa dinamis yang berjalan di browser dan memungkinkan kita untuk mengubah hampir setiap aspek dari cara kerja halaman: kita dapat memodifikasi konten dengan menambahkan dan menghapus elemen dari hierarki DOM; kita dapat memodifikasi properti CSSOM setiap elemen; kita dapat menangani input pengguna; dan banyak lagi. Untuk mengilustrasikan hal ini, lihat apa yang terjadi saat contoh "Hello World" sebelumnya diubah untuk menambahkan skrip inline singkat:

<!DOCTYPE html>
<html>
  <head>
    <meta name="viewport" content="width=device-width,initial-scale=1" />
    <link href="style.css" rel="stylesheet" />
    <title>Critical Path: Script</title>
  </head>
  <body>
    <p>Hello <span>web performance</span> students!</p>
    <div><img src="awesome-photo.jpg" /></div>
    <script>
      var span = document.getElementsByTagName('span')[0];
      span.textContent = 'interactive'; // change DOM text content
      span.style.display = 'inline'; // change CSSOM property
      // create a new element, style it, and append it to the DOM
      var loadTime = document.createElement('div');
      loadTime.textContent = 'You loaded this page on: ' + new Date();
      loadTime.style.color = 'blue';
      document.body.appendChild(loadTime);
    </script>
  </body>
</html>

Cobalah

  • JavaScript memungkinkan kita mengakses DOM dan mengambil referensi ke simpul bentang tersembunyi; simpul ini mungkin tidak terlihat di pohon render, namun masih ada di DOM. Selanjutnya, bila memiliki referensinya, kita bisa mengubah teksnya (lewat .textContent), dan bahkan mengganti properti gaya tampilan yang dihitungnya dari "none" menjadi "inline". Sekarang halaman kita menampilkan "Halo siswa interaktif!".

  • JavaScript juga memungkinkan kita untuk membuat, menata gaya, menambahkan, dan membuang elemen baru di DOM. Secara teknis, keseluruhan halaman kita bisa berupa satu file JavaScript besar saja yang membuat dan menata gaya elemen satu per satu. Meskipun itu bisa dilakukan, dalam praktiknya menggunakan HTML dan CSS jauh lebih mudah. Di bagian kedua fungsi JavaScript, kita membuat elemen div yang baru, menetapkan materi teksnya, menggayakannya, dan menambahkannya ke tubuh.

Pratinjau halaman yang dirender di perangkat seluler.

Dengan hal itu, kita telah memodifikasi materi dan gaya CSS dari node DOM yang ada, dan menambahkan seluruh node yang baru ke dokumen. Laman kita tidak akan memenangkan penghargaan desain, tetapi laman menggambarkan kemampuan dan fleksibilitas yang ditawarkan JavaScript kepada kita.

Namun, meskipun JavaScript menawarkan banyak kemampuan kepada kita, banyak batasan tambahan yang ditimbulkan dalam hal bagaimana dan kapan laman dirender.

Pertama, perhatikan bahwa dalam contoh sebelumnya, skrip inline kita ada di bagian bawah halaman. Mengapa? Anda harus mencobanya sendiri, tetapi jika kita memindahkan skrip di atas elemen <span>, Anda akan melihat bahwa skrip akan gagal dan mengeluh bahwa ia tidak dapat menemukan referensi ke elemen <span> dalam dokumen; yaitu, getElementsByTagName('span') menampilkan null. Ini mendemonstrasikan properti penting: skrip kita dieksekusi pada titik penyisipan yang tepat di dalam dokumen. Saat parser HTML menemukan tag skrip, parser akan menjeda proses konstruksi DOM dan menghasilkan kontrol atas mesin JavaScript; setelah mesin JavaScript selesai dijalankan, browser selanjutnya melanjutkan dari tempat terakhir dan meneruskan konstruksi DOM.

Dengan kata lain, blok skrip kita tidak dapat menemukan elemen apa pun di bagian bawah halaman karena belum diproses! Atau, dengan kata lain: mengeksekusi skrip inline akan memblokir konstruksi DOM, yang juga akan menunda render awal.

Properti samar lainnya dari pengenalan skrip ke dalam halaman kita adalah skrip dapat membaca dan mengubah tidak hanya DOM, tetapi juga properti CSSOM. Faktanya, itulah yang sebenarnya kita lakukan dalam contoh kita ketika kita mengubah properti tampilan dari elemen bentang dari none ke inline. Hasil akhirnya? Sekarang kita memiliki kondisi race.

Bagaimana jika browser belum selesai mendownload dan mem-build CSSOM saat kita ingin menjalankan skrip? Jawabannya tidak terlalu bagus untuk performa: browser menunda eksekusi skrip dan konstruksi DOM hingga selesai mendownload dan membangun CSSOM.

Singkatnya, JavaScript menimbulkan banyak dependensi baru di antara eksekusi DOM, CSSOM, dan JavaScript. Hal ini dapat menyebabkan penundaan browser secara signifikan dalam pemrosesan dan rendering halaman pada layar:

  • Lokasi skrip dalam dokumen sifatnya signifikan.
  • Saat browser menemukan tag skrip, konstruksi DOM akan berhenti sementara hingga skrip selesai dieksekusi.
  • JavaScript dapat melakukan kueri dan memodifikasi DOM dan CSSOM.
  • Eksekusi JavaScript akan berhenti sementara hingga CSSOM siap.

Secara garis besarnya, "mengoptimalkan jalur rendering penting" mengacu pada pemahaman dan pengoptimalan grafik dependensi antara HTML, CSS, dan JavaScript.

Pemblokiran parser versus JavaScript asinkron

Secara default, eksekusi JavaScript adalah "pemblokiran parser": saat browser menemukan skrip dalam dokumen, browser harus menjeda konstruksi DOM, menyerahkan kontrol ke runtime JavaScript, dan membiarkan skrip dieksekusi sebelum melanjutkan dengan konstruksi DOM. Kita melihat aksinya pada skrip inline dalam contoh kita sebelumnya. Faktanya, skrip inline selalu memblokir parser kecuali jika Anda menulis kode tambahan untuk menunda eksekusinya.

Bagaimana dengan skrip yang disertakan menggunakan tag skrip? Ambil contoh sebelumnya dan ekstrak kode ke dalam file terpisah:

<!DOCTYPE html>
<html>
  <head>
    <meta name="viewport" content="width=device-width,initial-scale=1" />
    <link href="style.css" rel="stylesheet" />
    <title>Critical Path: Script External</title>
  </head>
  <body>
    <p>Hello <span>web performance</span> students!</p>
    <div><img src="awesome-photo.jpg" /></div>
    <script src="app.js"></script>
  </body>
</html>

app.js

var span = document.getElementsByTagName('span')[0];
span.textContent = 'interactive'; // change DOM text content
span.style.display = 'inline'; // change CSSOM property
// create a new element, style it, and append it to the DOM
var loadTime = document.createElement('div');
loadTime.textContent = 'You loaded this page on: ' + new Date();
loadTime.style.color = 'blue';
document.body.appendChild(loadTime);

Cobalah

Baik kita menggunakan tag <script> atau cuplikan JavaScript inline, Anda akan mengharapkan keduanya berperilaku dengan cara yang sama. Dalam kedua kasus ini, browser menjeda dan mengeksekusi skrip sebelum dapat memproses bagian dokumen selanjutnya. Namun, untuk file JavaScript eksternal, browser harus dijeda untuk menunggu skrip diambil dari disk, cache, atau server jarak jauh, yang dapat menambah jeda dari puluhan hingga ribuan milidetik ke jalur rendering kritis.

Secara default, semua JavaScript memblokir parser. Browser tidak tahu apa yang akan dilakukan skrip pada halaman, sehingga harus beranggapan dengan skenario terburuk dan memblokir parser. Sinyal kepada browser bahwa skrip tidak perlu dieksekusi pada titik yang persis dengan yang direferensikan akan memungkinkan browser melanjutkan konstruksi DOM dan membiarkan skrip dieksekusi bila sudah siap; misalnya, setelah file diambil dari cache atau server jauh.

Untuk mencapainya, atribut async ditambahkan ke elemen <script>:

<!DOCTYPE html>
<html>
  <head>
    <meta name="viewport" content="width=device-width,initial-scale=1" />
    <link href="style.css" rel="stylesheet" />
    <title>Critical Path: Script Async</title>
  </head>
  <body>
    <p>Hello <span>web performance</span> students!</p>
    <div><img src="awesome-photo.jpg" /></div>
    <script src="app.js" async></script>
  </body>
</html>

Cobalah

Penambahan kata kunci async ke tag skrip akan memberi tahu browser agar tidak memblokir konstruksi DOM selagi menunggu skrip tersedia, yang secara signifikan bisa meningkatkan kinerja.

Masukan