Menambahkan Interaktivitas dengan JavaScript

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

Ringkasan

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

JavaScript adalah bahasa dinamis yang berjalan di browser dan memungkinkan kita untuk mengubah hampir setiap aspek dari cara laman berperilaku: kita bisa memodifikasi konten dengan menambah dan menghapus elemen dari pohon DOM; kita bisa memodifikasi properti WebView setiap elemen; kita bisa menangani input pengguna; dan banyak lagi. Untuk mengilustrasikan hal ini, mari kita perkaya contoh "Hello World" sebelumnya dengan skrip inline sederhana:

<!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 menjangkau DOM dan menarik referensi ke simpul bentang tersembunyi; simpul mungkin tidak terlihat di pohon render, namun masih ada di DOM. Lalu, saat kita memiliki referensi, kita bisa mengubah teksnya (melalui .textContent), dan bahkan mengganti properti gaya tampilan yang dihitung dari "none" menjadi "inline". Sekarang halaman kita akan menampilkan "Halo siswa interaktif!".

  • JavaScript juga memungkinkan kita untuk membuat, menata gaya, menambahkan, dan menghapus elemen baru dalam DOM. Secara teknis, keseluruhan halaman kita bisa berupa satu file JavaScript besar yang membuat dan menata gaya elemen satu per satu. Meskipun ini akan berhasil, 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 badan.

pratinjau halaman

Dengan itu, kita telah memodifikasi konten dan gaya CSS simpul DOM yang ada, dan menambahkan simpul yang sama sekali baru ke dokumen. Halaman kita tidak akan memenangkan penghargaan desain, tetapi halaman tersebut menggambarkan kekuatan dan fleksibilitas yang diberikan JavaScript kepada kita.

Namun, meskipun JavaScript memberi kita banyak kemampuan, cara ini menimbulkan banyak batasan tambahan tentang bagaimana dan kapan halaman dirender.

Pertama, perhatikan bahwa dalam contoh di atas, skrip inline kita berada di dekat bagian bawah halaman. Mengapa? Anda harus mencobanya sendiri, tetapi jika kita memindahkan skrip di atas elemen span, Anda akan melihat bahwa skrip gagal dan mengeluhkan bahwa skrip tidak dapat menemukan referensi ke elemen span apa pun dalam dokumen; yaitu, getElementsByTagName(‘span') akan menampilkan null. Ini mendemonstrasikan properti penting: skrip dieksekusi pada titik yang tepat tempat skrip disisipkan dalam dokumen. Ketika parser HTML menemukan tag skrip, parser akan menghentikan sementara proses konstruksi DOM dan menghasilkan kontrol ke mesin JavaScript; setelah mesin JavaScript selesai berjalan, browser kemudian melanjutkan dari tempat terakhirnya dan melanjutkan konstruksi DOM.

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

Properti halus lain dari memasukkan skrip ke dalam laman adalah bahwa skrip bisa membaca dan memodifikasi tidak hanya DOM, tetapi juga properti YAML. Faktanya, itulah yang kita lakukan dalam contoh kita saat mengubah properti tampilan elemen span dari tidak ada menjadi inline. Hasil akhirnya? Kita sekarang memiliki kondisi race.

Bagaimana jika browser belum selesai mengunduh dan membangun Orchestrator ketika kita ingin menjalankan skrip? Jawabannya sederhana dan tidak terlalu bagus untuk performa: browser menunda eksekusi skrip dan konstruksi DOM hingga selesai mendownload dan menyusun WebView.

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

  • Lokasi skrip dalam dokumen bersifat signifikan.
  • Saat browser menemukan tag skrip, konstruksi DOM akan dijeda hingga skrip selesai dieksekusi.
  • JavaScript dapat melakukan kueri dan memodifikasi DOM dan WebView.
  • Eksekusi JavaScript akan dijeda hingga WebView siap.

Secara umum, "mengoptimalkan jalur rendering penting" mengacu pada pemahaman dan pengoptimalan grafik ketergantungan 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 waktu proses JavaScript, dan membiarkan skrip dieksekusi sebelum melanjutkan dengan konstruksi DOM. Kita melihat ini beraksi dengan skrip {i>inline<i} dalam contoh kita sebelumnya. Faktanya, skrip inline selalu memblokir parser kecuali Anda menulis kode tambahan untuk menunda eksekusinya.

Bagaimana dengan skrip yang disertakan melalui tag skrip? Mari kita 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 kami menggunakan tag <script> maupun cuplikan JavaScript inline, Anda mengharapkan keduanya berperilaku dengan cara yang sama. Pada kedua kasus tersebut, browser akan menjeda dan mengeksekusi skrip sebelum dapat memproses sisa dokumen. Namun, dalam kasus file JavaScript eksternal, browser harus menjeda untuk menunggu skrip diambil dari disk, cache, atau server jarak jauh, yang dapat menambah penundaan puluhan hingga ribuan milidetik ke jalur rendering penting.

Secara default, semua JavaScript memblokir parser. Karena browser tidak tahu apa yang akan dilakukan skrip pada halaman, browser mengasumsikan skenario terburuk dan memblokir parser. Sebuah sinyal ke browser bahwa skrip tidak perlu dieksekusi pada titik acuan yang tepat memungkinkan browser untuk melanjutkan konstruksi DOM dan membiarkan skrip mengeksekusi saat skrip siap; misalnya, setelah file diambil dari cache atau server jarak jauh.

Untuk mencapainya, kita menandai skrip kita sebagai async:

<!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 selagi menunggu skrip tersedia, yang dapat meningkatkan performa secara signifikan.

Masukan