Dalam JavaScript, kita harus menggunakan variabel lokal sebanyak mungkin daripada variabel global. Semua orang tahu kalimat ini, tapi siapa yang mengatakannya pertama kali? Mengapa melakukan ini? Apakah ada dasar untuk ini? Jika Anda tidak melakukan ini, berapa banyak kerugian yang akan ditimbulkan terhadap kinerja? Artikel ini akan mengeksplorasi jawaban atas pertanyaan-pertanyaan ini dan memahami secara mendasar faktor-faktor apa saja yang terkait dengan kinerja membaca dan menulis variabel.
【Asli】 Performa variabel JavaScript
【Penulis】Nicholas C. Zakas
[Terjemahan] Dalam JavaScript, mengapa kita harus menggunakan variabel lokal bila memungkinkan?
[Penerjemah] Mingda
Berikut ini adalah terjemahan dari teks aslinya:
Mengenai masalah bagaimana meningkatkan kinerja JavaScript, saran yang paling sering didengar adalah menggunakan variabel lokal daripada variabel global. Ini adalah nasihat yang melekat pada saya dan tidak pernah mempertanyakannya selama sembilan tahun saya bekerja di pengembangan web, dan ini didasarkan pada penanganan metode pelingkupan dan resolusi pengidentifikasi (resolusi pengidentifikasi) JavaScript.
Pertama-tama, kita perlu memperjelas bahwa fungsi diwujudkan sebagai objek dalam JavaScript. Proses pembuatan fungsi sebenarnya adalah proses pembuatan objek. Setiap objek fungsi memiliki properti internal yang disebut [[Cakupan]], yang berisi informasi cakupan saat fungsi dibuat. Faktanya, atribut [[Scope]] berhubungan dengan daftar objek (Objek Variabel), dan objek dalam daftar dapat diakses dari dalam fungsi. Misalnya, jika kita membuat fungsi global A, maka properti internal [[Scope]] A hanya berisi satu objek global (Objek Global), dan jika kita membuat fungsi baru B di A, maka atribut [[Scope] ] B berisi dua objek, objek Objek Aktivasi fungsi A berada di depan, dan objek global (Objek Global) berada di belakang.
Ketika suatu fungsi dijalankan, objek yang dapat dieksekusi (Objek Eksekusi) secara otomatis dibuat dan diikat ke rantai cakupan (Rantai Lingkup). Rantai cakupan akan ditetapkan melalui dua langkah berikut untuk resolusi pengidentifikasi.
1. Pertama, salin objek di properti internal objek fungsi [[Scope]] ke rantai cakupan secara berurutan.
2. Kedua, ketika fungsi dijalankan, objek Objek Aktivasi baru akan dibuat. Objek ini berisi definisi, parameter (argumen), dan variabel lokal (termasuk parameter bernama). Objek Objek Aktivasi ini akan ditempatkan dalam tindakan . Bagian depan rantai domain.
Selama eksekusi kode JavaScript, ketika pengidentifikasi ditemukan, maka akan dicari dalam rantai lingkup konteks eksekusi (Konteks Eksekusi) berdasarkan nama pengidentifikasi. Dimulai dari objek pertama dalam rantai cakupan (Objek Aktivasi fungsi), jika tidak ditemukan, cari objek berikutnya dalam rantai cakupan, dan seterusnya, hingga definisi pengenal ditemukan. Jika objek terakhir dalam cakupan, yaitu Objek Global, tidak ditemukan setelah pencarian, kesalahan akan terjadi, yang memberitahu pengguna bahwa variabel tersebut tidak terdefinisi. Ini adalah model eksekusi fungsi dan proses resolusi pengidentifikasi (Resolusi Pengidentifikasi) yang dijelaskan dalam standar ECMA-262. Ternyata sebagian besar mesin JavaScript memang diimplementasikan dengan cara ini. Perlu dicatat bahwa ECMA-262 tidak mewajibkan penggunaan struktur ini, namun hanya menjelaskan bagian fungsi ini.
Setelah memahami proses resolusi pengidentifikasi (Resolusi Pengidentifikasi), kita dapat memahami mengapa variabel lokal diselesaikan lebih cepat dibandingkan variabel dalam cakupan lain, terutama karena proses pencariannya jauh lebih singkat. Tapi seberapa cepatnya? Untuk menjawab pertanyaan ini, saya menyimulasikan serangkaian pengujian untuk menguji kinerja variabel pada kedalaman cakupan yang berbeda.
Tes pertama adalah menulis nilai paling sederhana ke suatu variabel (di sini digunakan nilai literal 1). Hasilnya ditunjukkan pada gambar di bawah ini, yang sangat menarik:
Tidak sulit untuk melihat dari hasil bahwa ketika proses penguraian pengidentifikasi memerlukan pencarian mendalam, akan terjadi penurunan kinerja, dan tingkat kehilangan kinerja akan meningkat seiring dengan bertambahnya kedalaman pengidentifikasi. Tidak mengherankan, Internet Explorer memiliki kinerja terburuk (tetapi sejujurnya, ada beberapa perbaikan di IE 8). Perlu dicatat bahwa ada beberapa pengecualian di sini, Google Chrome dan WebKit versi tengah malam terbaru memiliki waktu akses yang sangat stabil ke variabel dan tidak bertambah seiring bertambahnya kedalaman cakupan. Tentu saja, ini harus dikaitkan dengan mesin JavaScript generasi berikutnya yang mereka gunakan, V8 dan SquirrelFish. Mesin ini melakukan optimasi saat mengeksekusi kode, dan jelas bahwa optimasi ini membuat pengaksesan variabel lebih cepat dari sebelumnya. Opera juga berkinerja baik, jauh lebih cepat dibandingkan IE, Firefox, dan Safari versi saat ini, namun lebih lambat dibandingkan browser berbasis V8 dan Squirrelfish. Performa Firefox 3.1 Beta 2 agak tidak terduga. Efisiensi eksekusi variabel lokal sangat tinggi, tetapi seiring bertambahnya jumlah lapisan cakupan, efisiensinya menurun drastis. Perlu dicatat bahwa saya menggunakan pengaturan default di sini, yang berarti Firefox tidak mengaktifkan fungsi Trace.
Hasil di atas diperoleh dengan melakukan operasi tulis pada variabel. Sebenarnya saya penasaran apakah situasinya akan berbeda saat membaca variabel, jadi saya melakukan tes berikut. Ditemukan bahwa kecepatan membaca sedikit lebih cepat daripada kecepatan menulis, namun tren perubahan kinerjanya konsisten.
Seperti pada pengujian sebelumnya, Internet Explorer dan Firefox masih yang paling lambat, dan Opera menunjukkan kinerja yang sangat menarik. Demikian pula, Chrome dan versi terbaru Webkit Midnight Edition menunjukkan tren kinerja yang tidak ada hubungannya dengan kedalaman cakupan patut diperhatikan. Ya, waktu akses variabel di Firefox 3.1 Beta 2 masih mengalami lompatan yang aneh.
Selama pengujian, saya menemukan fenomena menarik, yaitu Chrome akan mengalami penurunan kinerja tambahan saat mengakses variabel global. Waktu untuk mengakses variabel global tidak ada hubungannya dengan tingkat cakupan, tetapi akan 50% lebih lama dibandingkan waktu untuk mengakses variabel lokal pada tingkat yang sama.
Pencerahan apa yang dapat kita peroleh dari kedua ujian ini? Yang pertama adalah memverifikasi sudut pandang lama, yaitu menggunakan variabel lokal sebanyak mungkin. Di semua browser, mengakses variabel lokal lebih cepat dibandingkan mengakses variabel lintas cakupan, termasuk variabel global. Poin-poin berikut harus menjadi pengalaman yang diperoleh melalui pengujian ini:
* Periksa dengan cermat semua variabel yang digunakan dalam fungsi. Jika ada variabel yang tidak ditentukan dalam cakupan saat ini dan digunakan lebih dari satu kali, maka kita harus menyimpan variabel tersebut di a variabel lokal, gunakan variabel lokal ini untuk melakukan operasi baca dan tulis. Hal ini dapat membantu kita mengurangi kedalaman pencarian variabel di luar cakupan menjadi 1. Hal ini sangat penting terutama untuk variabel global, karena variabel global selalu dicari pada posisi terakhir rantai cakupan.
* Hindari menggunakan pernyataan with. Karena akan mengubah rantai lingkup konteks eksekusi (Execution Context) dan menambahkan objek (Variable Object) di depannya. Artinya selama eksekusi with, variabel lokal aktual dipindahkan ke posisi kedua dalam rantai cakupan, yang akan menyebabkan hilangnya performa.
* Jika Anda yakin bahwa suatu bagian kode pasti akan memunculkan pengecualian, maka hindari penggunaan try-catch, karena cabang catch diproses dalam rantai cakupan yang sama dengan with. Namun, tidak ada penurunan kinerja dalam kode cabang try, jadi tetap disarankan untuk menggunakan try-catch untuk menangkap kesalahan yang tidak terduga.
Jika Anda ingin diskusi lebih lanjut seputar topik ini, saya memberikan ceramah kecil di Mountain View JavaScript Meetup bulan lalu. Anda dapat mengunduh slidenya di SlideShare, atau menonton video lengkap pesta tersebut, yang dimulai sekitar 11 menit dari pembicaraan saya.
Catatan Penerjemah:
Jika Anda ragu saat membaca artikel ini, saya sarankan Anda membaca dua artikel berikut:
* "Model Eksekusi Model Objek JavaScript" ditulis oleh Richie
* "ECMA-262 Edisi Ketiga", terutama lihat Bab 10, yang merupakan Konteks Eksekusi. Istilah-istilah yang disebutkan dalam artikel ini dijelaskan secara rinci di sana.
Di akhir, Nicholas menyebutkan Pertemuan JavaScript Mountain View. Situs web Meetup sebenarnya adalah situs web organisasi untuk berbagai aktivitas dunia nyata. Anda perlu melewati firewall untuk mengaksesnya kegiatan yang harus diikuti. hehe.