Web Workers — Performance

Web Workers Web Workers memungkinkan kita menjalankan JavaScript di thread terpisah dari main thread. Ini mencegah heavy computation dari memblokir UI. Kapan…

Web Worker adalah thread JavaScript kedua yang jalan di samping main thread. Kerja berat dipindah ke sana, jadi main thread tetap bebas merespons klik dan menggambar layar. Bayangin dapur restoran yang kokinya juga melayani tamu di depan. Ada pesanan 50 kg bawang yang harus dipotong, jadi dia minta tolong asisten di dapur belakang. Asisten itu worker: dia gak bisa keluar ke ruang tamu, cuma menerima pesanan lewat kertas dan mengirim hasilnya lewat kertas juga.

🧪 Tebakan cepat: menghitung statistik 100.000 transaksi butuh 1.500 ms. Kerja itu dipindah ke Web Worker. Hasilnya muncul kapan: jauh lebih cepat (sekitar 750 ms), sekitar 1.500 ms, atau langsung? Jawabannya ada di bagian "Main thread lawan worker".

Main thread lawan worker

Dari pelajaran sebelumnya: main thread cuma satu, dan selama dia menjalankan satu task, klik harus antre. Worker punya thread sendiri, jadi kerja di sana gak menahan main thread.

Angka simulasi dari Lab di halaman ini: hitung statistik 1.500 ms, lalu tampilkan hasilnya 10 ms. Kamu klik tombol Like di ms ke-500.

Dihitung di main thread Dihitung di Web Worker
Main thread sibuk 1.510 ms tanpa jeda 40 ms kirim data, lalu 10 ms tampilkan hasil
Klik Like di ms ke-500 nunggu 1.010 ms langsung diproses
Hasil tampil ms ke-1.510 ms ke-1.591

Di worker, hasilnya tetap butuh sekitar 1.500 ms, malah sedikit lebih lama karena ada ongkos kirim data bolak-balik. Itu jawaban tebakannya. Worker gak bikin JavaScript lebih cepat. Untungnya: selama 1.500 ms itu halamannya tetap responsif, jadi Like langsung bertambah.

Membuat worker

Kode worker ditulis di file terpisah. Main thread dan worker saling bicara lewat pesan.

// main.js
const worker = new Worker("statistik.js");

tombolHitung.addEventListener("click", () => {
  worker.postMessage(transaksi); // kirim 100.000 transaksi
});

worker.onmessage = (event) => {
  tampilkan(event.data); // hasil dari worker
};

// statistik.js (jalan di worker)
self.onmessage = (event) => {
  const transaksi = event.data;
  const total = transaksi.reduce((jumlah, t) => jumlah + t.nominal, 0);
  self.postMessage({ total, rataRata: total / transaksi.length });
};

Yang gak bisa dilakukan worker

Worker gak punya akses ke DOM: di dalamnya gak ada document dan gak ada window. Menulis document.querySelector("#hasil") di worker langsung error: ReferenceError: document is not defined. Jadi worker cuma menghitung, lalu mengirim hasilnya. Yang mengubah tampilan tetap main thread, di worker.onmessage.

Yang tetap bisa: fetch, setTimeout, IndexedDB, WebSocket, dan semua hitungan biasa. Cocok untuk parsing data besar (JSON, CSV), olah gambar, enkripsi atau hashing, dan sorting data yang banyak.

Data dikopi atau dipindah

postMessage mengkopi datanya dengan cara yang disebut structured clone. Object, array, Map, Date, dan ArrayBuffer bisa dikirim. Function dan elemen DOM gak bisa: postMessage langsung melempar DataCloneError. Karena dikopi, mengubah object aslinya setelah dikirim gak mengubah salinan di worker. Mengkopi juga ada ongkosnya: di Lab, 100.000 object butuh 40 ms di main thread.

Data biner di ArrayBuffer bisa dipindah (transfer), bukan dikopi. Hampir gratis, tapi setelah itu pengirimnya gak punya datanya lagi.

const nominal = new Float64Array(100000); // 800 KB angka
worker.postMessage(nominal.buffer, [nominal.buffer]);
console.log(nominal.buffer.byteLength); // 0, sudah pindah ke worker

Ada juga SharedArrayBuffer untuk memori yang dipakai bersama oleh dua thread, tapi dia butuh header cross-origin isolation di server dan jarang dibutuhkan.

⚠️ Jebakan yang sering ketemu

TL;DR: Web Worker menjalankan JavaScript di thread terpisah, jadi kerja berat gak menahan main thread dan halaman tetap responsif. Kerjanya gak jadi lebih cepat (1.500 ms tetap sekitar 1.500 ms), tapi klik gak perlu antre. Buat dengan new Worker("file.js"), kirim dengan postMessage, terima di onmessage, dan matikan dengan terminate(). Worker gak bisa mengakses DOM (document dan window gak ada), jadi dia mengirim hasilnya dan main thread yang mengubah tampilan. Data dikopi lewat structured clone (function dan elemen DOM gak bisa), dan ArrayBuffer bisa dipindah lewat daftar transfer sehingga byteLength di pengirim jadi 0.

Yang akan kamu pelajari