Petunjuk dan konteks
Sebuah konsol admin memungkinkan pengguna membuka beberapa tab. Setelah pengguna logout, mengubah tema, atau memperbarui notifikasi di satu tab, tab lain harus segera melakukan konvergensi. Refresh, tab yang tidak aktif (sleeping tabs), pesan duplikat, dan browser tanpa BroadcastChannel tidak boleh merusak state akhir. Rancang protokol, pemulihan, fallback, dan metrik verifikasinya.
Ini adalah pertanyaan koordinasi browser untuk peran frontend, platform web, dan desain sistem frontend. Jumlah tab, penundaan sinkronisasi, dan tipe event adalah asumsi wawancara, bukan jaminan browser. Fokuslah pada batas same-origin dan partisi penyimpanan BroadcastChannel, konsekuensi pesan non-persisten, pilihan event versus state, dan kapan harus menggabungkannya dengan localStorage, IndexedDB, SharedWorker, atau Web Locks.
Apa yang sedang diuji oleh pewawancara
Pertama, dapatkah Anda menyatakan batas API? BroadcastChannel mengirim pesan antar jendela, tab, frame, dan worker yang berbagi origin dan partisi penyimpanan yang dapat dikomunikasikan. Ini bukan transport cross-origin, antrean persisten, atau layanan konsistensi terdistribusi.
Kedua, dapatkah Anda merancang protokol idempoten? Pesan dapat terduplikasi, pengirim tidak menerima siarannya sendiri, dan halaman penerima mungkin ditutup atau tidak aktif (sleep). Pesan yang hanya mengatakan "tema telah berubah" tanpa versi dan jalur pembacaan ulang akan membuat state menjadi basi (stale) secara permanen.
Ketiga, dapatkah Anda memisahkan notifikasi dari sumber kebenaran (source of truth)? Logout dapat menyiarkan pembatalan (invalidation), perubahan tema dapat dipersistensikan lalu diumumkan, dan pembaruan notifikasi harus membuat penerima membaca ulang cache otoritatif daripada memperlakukan daftar lengkap dalam pesan sebagai kebenaran.
Terakhir, dapatkah Anda menangani siklus hidup dan fallback: menutup channel, menjaga token agar tidak masuk ke dalam pesan, mendeteksi kapabilitas, menggunakan event penyimpanan atau pembacaan ulang server, serta mengukur bahwa sinkronisasi tidak menciptakan perulangan (loop) atau kebocoran memori?
Pertanyaan klarifikasi awal
- Apakah payload berupa event satu kali, state saat ini, atau riwayat yang dapat diputar ulang? Hal ini menentukan apakah versi persisten diperlukan.
- Apakah cakupannya adalah satu origin, iframe di bawah situs level teratas yang sama, atau subdomain yang berbeda? Partisi penyimpanan dapat mencegah komunikasi bahkan ketika origin tampak terkait.
- Bisakah satu pesan hilang? Logout, pencabutan izin, dan konflik pengeditan memerlukan jaminan pemulihan yang berbeda.
- Di mana sumber kebenarannya: server, IndexedDB, localStorage, cache dalam memori, atau Service Worker?
- Haruskah satu tab menjadi satu-satunya penulis untuk refresh, migrasi, atau pekerjaan batch? BroadcastChannel tidak menyediakan mekanisme penguncian (lock).
- Bagaimana matriks browsernya, termasuk mode privat, pembekuan di latar belakang, dan perkiraan jumlah tab?
- Mungkinkah sebuah pesan berisi data profil, izin, atau token? Jika demikian, gantilah dengan sinyal pembatalan yang tidak sensitif.
Jawaban 30 detik
"Saya akan menggunakan BroadcastChannel sebagai bus notifikasi dengan latensi rendah, bukan sebagai sumber state yang persisten. Setiap pesan membawa versi protokol, tipe event, urutan monotonik atau versi state, dan trace ID. Penerima memvalidasi bentuk data, menerapkan event secara idempoten, dan membaca ulang localStorage, IndexedDB, atau server ketika celah versi muncul. Logout mengirimkan invalidasi, tema menulis preferensi persisten, dan perubahan notifikasi memicu pembacaan ulang. Jika API tidak tersedia, gunakan event penyimpanan atau polling; jika diperlukan satu penulis, gunakan Web Locks atau koordinasi server. Tutup setiap channel saat teardown dan ukur latensi, pemulihan pesan yang hilang, serta penanganan duplikat."
Jawaban langkah demi langkah
Langkah 1: Tentukan pesan dan state otoritatif
Tetapkan sumber kebenaran per fitur. Tema dan bahasa adalah preferensi yang dapat disimpan dalam pengaturan persisten. Notifikasi dan izin harus dibaca ulang dari server atau cache lokal. Logout adalah sinyal invalidasi sesi; jangan pernah memasukkan token akses ke dalam pesan. Siarkan hanya type, version, entityKey, updatedAt, atau traceId yang tidak sensitif.
MDN menjelaskan bahwa BroadcastChannel mendukung komunikasi dua arah antara konteks penjelajahan same-origin dan worker, sementara aplikasi menentukan protokol pesan; platform tidak menyediakan negosiasi. Pembuatan versi, penanganan event yang tidak dikenal, dan validasi field adalah tanggung jawab aplikasi.
Langkah 2: Tangani duplikat, pengurutan, dan kehilangan pesan
Pertahankan versi terakhir yang diproses untuk setiap domain state. Abaikan pesan yang versinya lebih lama atau sama; versi baru yang berurutan dapat memicu satu kali pembacaan ulang; lonjakan versi menandakan adanya celah dan memulai sinkronisasi snapshot. Jika kebutuhan bisnis mengekspos event tanpa versi, gunakan ID deduplikasi dan set pemrosesan yang dibatasi, sambil menyadari bahwa ini tidak dapat membuktikan bahwa event perantara tidak hilang.
Jangan mengasumsikan pesan pasti terkirim. Pengirim tidak menerima pesannya sendiri, dan tab yang baru dibuka atau sedang tidak aktif dapat melewatkannya. Saat startup, muat state persisten atau snapshot server sebelum berlangganan; siaran hanya mengurangi latensi pembaruan data.
Langkah 3: Pilih persistensi dan koordinasi secara bersamaan
localStorage cocok untuk preferensi kecil dan dapat memicu storage event; ini bukan database throughput tinggi atau tempat untuk menyimpan token. IndexedDB cocok untuk cache lokal yang lebih besar dan snapshot berversi. Service Worker dapat berpartisipasi dalam sinkronisasi latar belakang, tetapi harus menulis hasilnya ke penyimpanan yang dapat dipulihkan.
BroadcastChannel menyelesaikan masalah notifikasi ke beberapa konteks, bukan koordinasi penulis tunggal (single-writer). Jika hanya satu tab yang boleh me-refresh cache, menjalankan migrasi, atau mengirimkan batch, gunakan Web Locks. Tanpa lock, sertakan kondisi versi dan biarkan server melakukan arbitrase. SharedWorker cocok untuk koneksi bersama atau state terpusat, tetapi menambah kompleksitas siklus hidup dan kompatibilitas.
Langkah 4: Bangun penerimaan yang aman dan fallback
Hanya terima tipe event yang ada dalam allowlist, batasi ukuran pesan, dan tolak versi yang tidak dikenal atau skema yang tidak valid. Jangan pernah menempatkan token akses, profil lengkap, atau HTML yang dapat dieksekusi di dalam pesan. Saat logout, bersihkan cache lokal yang sensitif dan navigasikan ke halaman masuk; pada event tema, perbarui UI tetapi percayai pengaturan yang dipersistensikan.
Jika deteksi kapabilitas gagal, gunakan storage event untuk state berukuran kecil. Jika itu tidak tersedia atau terpartisi, baca ulang saat fokus, lakukan polling singkat, atau gunakan push server. Fallback harus aman untuk diulang; ketiadaan siaran tidak boleh menyebabkan perbedaan data yang permanen.
Langkah 5: Kelola sumber daya dan verifikasi perilaku
Hapus listener dan panggil close() saat komponen atau halaman dimusnahkan. Jangan membuat channel baru pada setiap render. Gunakan namespace agar aplikasi yang tidak terkait tidak berlangganan ke nama yang sama. Sertakan label sumber dan trace ID agar penerima tidak menyiarkan ulang pesan yang sama dalam sebuah loop.
Uji latensi end-to-end multi-tab, duplikat dan pengurutan ulang, pemulihan setelah sleep, snapshot awal setelah refresh, fallback penyimpanan, isolasi partisi penyimpanan, penutupan channel, pesan yang terlalu besar, loop, dan pergantian pengguna. Lacak keberhasilan handler, celah versi, pembacaan ulang, duplikat yang dibuang, waktu pemulihan, dan channel yang dibiarkan terbuka.
Contoh jawaban berkualitas tinggi
"Saya akan mendefinisikan BroadcastChannel sebagai bus notifikasi, bukan antrean. Logout hanya membawa tipe invalidasi sesi dan versi. Pembaruan tema menulis ke localStorage dan menyiarkan versi preferensi baru. Pembaruan notifikasi menyiarkan kunci entitas dan versi, sehingga setiap penerima membaca ulang dari server atau IndexedDB. Pesan tidak berisi token atau data pengguna yang lengkap.
Setiap pesan memiliki versi protokol, versi state monotonik, dan trace ID. Penerima menolak struktur yang tidak dikenal, membuang versi yang sudah diproses atau lebih lama, dan mengambil snapshot saat melihat celah versi. Startup memuat snapshot sebelum berlangganan karena tab baru atau yang sedang tidak aktif dapat melewatkan siaran, dan pengirim tidak menerima pesannya sendiri.
Jika pembaruan cache memerlukan satu penulis, saya akan menambahkan Web Locks; BroadcastChannel saja tidak dapat mencegah dua tab menulis secara bersamaan. Browser yang tidak didukung menggunakan storage event untuk preferensi kecil dan pembacaan ulang saat fokus atau short polling untuk data lainnya. Teardown menghapus listener dan menutup channel. Metrik mencakup latensi, celah versi, duplikat, waktu pemulihan, dan kebocoran sumber daya. Pendekatan ini memisahkan notifikasi latensi rendah, state yang dapat dipulihkan, dan kompatibilitas browser."
Pola kegagalan umum
- Memperlakukan siaran sebagai antrean persisten → tab baru atau tab yang tidak aktif melewatkan event → muat snapshot terlebih dahulu dan gunakan pesan sebagai petunjuk (hint).
- Menaruh token atau state lengkap dalam pesan → memperluas paparan data sensitif dan konflik versi → kirim hanya event, kunci, dan versi yang tidak sensitif.
- Tanpa versi atau ID deduplikasi → duplikat dan pengurutan ulang membuat UI mundur ke state lama → gunakan versi monotonik, penanganan idempoten, dan pembacaan ulang saat ada celah.
- Mengasumsikan same-origin berarti konektivitas terjamin → partisi penyimpanan dapat mengisolasi konteks → uji batasan sebenarnya dan sediakan fallback.
- Menggunakan BroadcastChannel sebagai lock → dua tab masih dapat menulis secara bersamaan → gunakan Web Locks atau conditional write di sisi server.
- Membuat channel di setiap render → listener dan sumber daya mengalami kebocoran → pertahankan instance yang stabil, hapus listener, dan tutup channel.
- Menyiarkan ulang setiap pesan yang diterima → menciptakan loop tak berujung → sertakan ID sumber/trace dan kirim hanya pada perubahan state.
- Memperlakukan storage event sebagai pengganti penuh → mereka hanya mencakup sebagian penulisan dan tidak memicu di jendela yang sama → dokumentasikan perbedaannya dan tambahkan pembacaan ulang.
Pertanyaan lanjutan
Pertanyaan lanjutan 1: Dua tab mengedit formulir yang sama. Bagaimana Anda menghindari penimpaan data (overwriting)?
Siarkan bahwa versi sumber daya telah berubah; jangan menimpa draf lokal. Kirimkan versi dasar, biarkan server menolak penulisan kondisional yang basi, dan tampilkan konflik untuk penggabungan manual oleh pengguna. Preferensi lokal dapat menggunakan Web Locks untuk serialisasi penulisan.
Pertanyaan lanjutan 2: Sebuah tab aktif kembali setelah tidak aktif (sleep) selama 20 menit. Bagaimana cara tab tersebut mengejar ketertinggalan?
Baca ulang snapshot server atau IndexedDB saat aktif kembali, bandingkan versi state, lalu proses sinyal inkremental apa pun. Jangan bergantung pada siaran terakhir. Jika snapshot tidak tersedia, tandai state sebagai basi dan minta validasi ulang atau tampilkan status kedaluwarsa yang jelas.
Pertanyaan lanjutan 3: Halaman pada subdomain yang berbeda perlu berkomunikasi. Apakah BroadcastChannel menyelesaikannya?
Jangan berasumsi demikian. BroadcastChannel dibatasi oleh origin dan partisi penyimpanan. Komunikasi cross-origin memerlukan relasi window postMessage yang eksplisit atau koordinasi server, dengan pemeriksaan origin, skema, dan izin; jangan melemahkan batas keamanan hanya untuk berbagi channel.
Pertanyaan lanjutan 4: Hanya satu tab yang boleh mempertahankan WebSocket. Bagaimana Anda merancangnya?
BroadcastChannel dapat berbagi status koneksi dan data tetapi tidak dapat memilih leader. Utamakan Web Locks untuk pemegang koneksi, dengan tab lain berlangganan ke siarannya; lakukan pemilihan ulang setelah pemegang menutup tab atau kehilangan lock. Jika tidak tersedia, gunakan lease server atau izinkan beberapa koneksi dengan deduplikasi di sisi server dan trade-off biaya yang eksplisit.