Menambahkan Interaktivitas dengan JavaScript

Dipublikasikan: 31 Desember 2013

JavaScript memungkinkan kita untuk memodifikasi hampir semua aspek halaman: konten, gaya visual, dan responsnya terhadap interaksi pengguna. Namun, JavaScript juga dapat memblokir konstruksi DOM dan menunda saat halaman dirender. Untuk memberikan hasil optimal performa, jadikan JavaScript Anda asinkron dan hilangkan setiap JavaScript yang tidak penting dari jalur rendering kritis.

Ringkasan

  • JavaScript bisa melakukan kueri dan memodifikasi DOM dan CMake.
  • Eksekusi JavaScript akan memblokir di CSSOM.
  • JavaScript memblokir konstruksi DOM kecuali secara tegas dideklarasikan sebagai asinkron.

JavaScript adalah bahasa dinamis yang berjalan di browser dan memungkinkan kita untuk mengubah hampir setiap aspek cara halaman berperilaku: kita bisa memodifikasi konten dengan menambah dan menghapus elemen dari hierarki DOM; kita bisa memodifikasi properti GCLID dari setiap elemen; kita dapat menangani input pengguna; dan masih 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 akan 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 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 baru, menetapkan konten teksnya, menata gayanya, dan menambahkannya ke isi.

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, namun laman menggambarkan kemampuan dan fleksibilitas yang diberikan 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 nanti di halaman karena belum diproses! Atau, dengan kata lain: mengeksekusi skrip inline akan memblokir konstruksi DOM, yang juga akan menunda render awal.

Properti halus lainnya dalam memasukkan skrip ke dalam laman kita adalah bahwa skrip dapat membaca dan memodifikasi tidak hanya DOM, tetapi juga properti GCLID. Sebenarnya, itulah yang kita lakukan dalam contoh kita ketika kita mengubah properti tampilan elemen span dari none menjadi inline. Hasil akhirnya? Kita sekarang memiliki kondisi race.

Bagaimana jika browser belum selesai mengunduh dan membangun GCLID ketika kita ingin menjalankan skrip kita? Jawabannya tidak terlalu bagus untuk kinerja: browser akan menunda eksekusi skrip dan konstruksi DOM hingga ia selesai mendownload dan membangun GCLID.

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

  • Lokasi skrip dalam dokumen bersifat 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 dihentikan sementara hingga GCLID siap.

Secara garis besar, "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 cara kerjanya 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 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

Apakah kita menggunakan <script> atau cuplikan JavaScript inline, Anda akan mengharapkan keduanya bekerja 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 menjeda 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. Karena tidak mengetahui rencana tindakan skrip pada halaman, browser mengasumsikan 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 mencapai hal ini, 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

Menambahkan kata kunci asinkron ke tag skrip akan memberi tahu browser agar tidak memblokir konstruksi DOM saat menunggu skrip tersedia, yang dapat meningkatkan performa secara signifikan.

Masukan