Perintah dan skenario yang berlaku
Halaman checkout e-commerce berperilaku berbeda di berbagai navigasi riwayat. Terkadang tombol Back memulihkan DOM persis, nilai form, posisi scroll, dan JavaScript heap hampir seketika. Cuplikan yang dipulihkan tersebut dapat berisi total keranjang yang basi atau sesi yang telah keluar di tab lain. Di lain waktu, Back membuat dokumen baru dan menjalankan jalur pemuatan normal. Tim telah menggunakan istilah "cache peramban" untuk menggambarkan semua hasil ini dan telah mempertimbangkan untuk menonaktifkan caching secara global.
Jelaskan bagaimana back/forward cache, atau bfcache, berbeda dari cache HTTP dan cache router SPA. Kemudian rancang rencana siklus hidup dan debugging yang:
- mendeteksi pemulihan bfcache yang terkonfirmasi secara terpisah dari pemuatan dokumen biasa;
- memvalidasi ulang autentikasi, keranjang, dan status sensitif lainnya sebelum mengizinkan tindakan yang berdampak;
- melepaskan sumber daya saat halaman disembunyikan dan menghubungkannya kembali tepat satu kali setelah pemulihan;
- menemukan pemblokir kelayakan (eligibility blockers) di halaman, frame turunan, dan kode pihak ketiga;
- mengukur penelusuran riwayat, pemulihan yang dikonfirmasi, misses, dan alasan pemblokiran berdasarkan versi peramban;
- mempertahankan manfaat performa jika kompatibel dengan kebijakan keamanan produk.
Pertanyaan ini berlaku untuk wawancara frontend senior, performa web, platform peramban, dan arsitektur frontend. Ini menguji apakah kandidat dapat menganalisis dokumen yang dijeda (paused), bukan hanya menghafal header cache.
Hal yang dievaluasi pewawancara
Pertama, kandidat harus membedakan tiga mekanisme yang berbeda. Cache HTTP menyimpan respons yang dapat digunakan kembali dan menerapkan aturan permintaan, kesegaran (freshness), dan validasi ulang. bfcache dapat mempertahankan seluruh halaman lintas-dokumen di memori, termasuk DOM dan JavaScript heap-nya, lalu menjeda dan melanjutkannya untuk penelusuran riwayat sesi. Router klien dapat mempertahankan data aplikasi atau UI untuk navigasi lunak (soft navigation) tanpa membuat atau memulihkan dokumen yang dikelola peramban. Mengosongkan satu cache bukanlah diagnosis untuk cache yang lain.
Kedua, kandidat harus memahami bukti siklus hidup. pageshow juga terpicu pada pemuatan awal, sehingga peristiwa itu sendiri bukanlah bukti. Peristiwa pageshow yang nilai persisted-nya adalah true mengonfirmasi bahwa dokumen dipulihkan dari cache seperti bfcache. Pada pagehide, persisted: true berarti peramban berniat untuk mempertahankan halaman; ini tidak menjamin halaman akan tetap di-cache atau nantinya akan dipulihkan.
Ketiga, jawaban yang kuat memperlakukan pemulihan sebagai batas kebenaran (correctness boundary). Timer dan nilai dalam memori dilanjutkan dari momen sebelumnya. Otorisasi tetap menjadi wewenang server, dan status sensitif harus divalidasi ulang pada pemulihan yang dikonfirmasi. Koneksi langsung, handel basis data, observer, dan lock mungkin perlu ditutup atau diputuskan sebelum navigasi dan dibuka kembali setelah kembali. Kode penyambungan kembali harus bersifat idempoten.
Keempat, kandidat harus mendebug dengan bukti alih-alih daftar pemblokir universal. Kelayakan berubah berdasarkan peramban, versi, frame, API, kebijakan respons, tekanan memori, dan skenario navigasi. Chrome DevTools dapat menjalankan pengujian bfcache terisolasi dan mengklasifikasikan pemblokir. Jika didukung, PerformanceNavigationTiming.notRestoredReasons menambahkan bukti lapangan dan pohon frame, tetapi string alasannya dapat berubah dan detail lintas-asal (cross-origin) dapat disamarkan.
Terakhir, kandidat harus menentukan hasil yang terukur. Penelusuran riwayat yang dilaporkan sebagai back_forward bukanlah bukti hit bfcache itu sendiri. Hit yang dikonfirmasi berasal dari pageshow.persisted. Misses adalah pemuatan dokumen baru yang dicapai melalui penelusuran riwayat, dan penyebabnya harus disegmentasi daripada ditebak. Tujuannya adalah cakupan pemulihan aman yang lebih tinggi tanpa tindakan sesi basi, koneksi ganda, atau analitik yang terdistorsi.
Pertanyaan yang perlu diklarifikasi sebelum menjawab
- Navigasi mana yang terlibat? Apakah ini navigasi dokumen penuh, perubahan rute SPA lunak, pemuatan ulang (reload), tab yang dibuka kembali, atau penelusuran Back/Forward nyata di tab yang sama?
- Apa yang boleh bertahan dengan aman? Draf form dan posisi scroll mungkin diinginkan; autentikasi, harga, inventaris, izin, dan token sekali pakai memerlukan aturan kesegaran yang otoritatif.
- Apa yang diwajibkan oleh kebijakan respons? Beberapa halaman berisi data yang dilarang oleh kebijakan produk untuk disimpan dalam snapshot halaman. Persyaratan tersebut lebih diutamakan daripada rasio hit.
- Sumber daya mana yang tetap aktif? WebSocket inventaris, koneksi IndexedDB, Web Locks, pengambilan media, observer, dan skrip pihak ketiga dapat memengaruhi kebenaran atau kelayakan.
- Peramban dan versi mana yang penting? Output DevTools dan
notRestoredReasonsbukanlah kontrak portabel. Uji matriks peramban yang didukung dengan navigasi riwayat nyata. - Apakah ada frame turunan? Turunan dengan asal yang sama (same-origin) dapat mengekspos pohon pemblokir yang mendetail. Frame lintas-asal mungkin hanya menampilkan informasi yang disamarkan, sehingga memerlukan isolasi vendor atau reproduksi minimal.
- Apa yang dimaksud dengan "stale"? Tentukan batas usia maksimum yang dapat diterima dan tindakan yang diblokir selama validasi ulang gagal.
- Bagaimana analitik dihitung? Tentukan apakah halaman yang dipulihkan dihitung sebagai page view, navigasi, atau keduanya, lalu cegah satu pemulihan memancarkan peristiwa duplikat.
- Apa gerbang keberhasilannya (success gate)? Lacak rasio pemulihan yang dikonfirmasi di antara penelusuran riwayat yang dapat diamati, alasan miss, latensi pemulihan, kegagalan validasi ulang, pencegahan tindakan basi, dan jumlah sumber daya duplikat.
Kerangka jawaban 30 detik
"Saya memisahkan bfcache dari cache HTTP dan router: bfcache menjeda dokumen untuk navigasi riwayat yang dikelola peramban. Saya mengonfirmasi hit hanya dengan pageshow.persisted, menggunakan pagehide untuk pembersihan idempoten tanpa berasumsi akan ada pemulihan. Saat pemulihan, saya memvalidasi ulang sesi, keranjang, harga, dan izin sebelum tindakan sensitif, lalu menghubungkan kembali sumber daya sekali saja. Saya mereproduksi misses di peramban yang didukung, menggunakan panel bfcache Chrome dan data notRestoredReasons yang tersedia, serta mensegmentasi metrik lapangan berdasarkan peramban dan rute. Saya mengoptimalkan halaman yang aman sambil tetap menjadikan otorisasi server dan kebijakan no-snapshot sebagai hal yang otoritatif."
Pembahasan mendalam langkah demi langkah
Langkah 1: Modelkan empat jalur yang dapat diamati
Mulailah dengan hasil daripada header:
| Jalur | Dokumen baru? | Bukti utama | Penanganan yang diperlukan |
|---|---|---|---|
| Navigasi awal atau tautan | Ya | pageshow.persisted === false; jenis navigasi biasanya navigate | Inisialisasi status dan sumber daya |
| Muat ulang (reload) | Ya | pageshow.persisted === false; jenis navigasi reload | Jalankan jalur pemuatan normal |
| Penelusuran riwayat dengan muat ulang | Ya | pageshow.persisted === false; jenis navigasi back_forward | Catat miss bfcache dan periksa alasannya |
| Pemulihan bfcache terkonfirmasi | Tidak | pageshow.persisted === true | Validasi ulang status sensitif dan lanjutkan dengan aman |
Jenis navigasi menjelaskan bagaimana dokumen baru dicapai. Ini tidak dapat mengonfirmasi hit bfcache karena hit melanjutkan dokumen lama. Namun, ini dapat mengidentifikasi pemuatan baru yang disebabkan oleh penelusuran riwayat dan oleh karena itu berkontribusi pada penyebut miss (miss denominator). Membuka ulang peramban, duplikasi tab, dan alur pembukaan kembali dapat mengaburkan sinyal ini, jadi metrik lapangan harus menyertakan peramban, versi, rute, dan skenario jika tersedia.
bfcache juga berbeda dari validasi ulang HTTP. Saat pemulihan, peramban melanjutkan halaman di memori; Cache-Control: no-cache tidak memaksa validasi jaringan sebelum piksel muncul. Jika konten yang dipulihkan harus mutakhir, aplikasi melakukan pemeriksaan terarah setelah pageshow. Navigasi lunak SPA mengubah riwayat dan UI di dalam dokumen yang sama; bfcache menjadi relevan ketika dokumen itu sendiri ditinggalkan dan kemudian dipulihkan.
Langkah 2: Buat pekerjaan siklus hidup menjadi idempoten dan restore-safe
Pusatkan kepemilikan koneksi. Pembersihan dapat diikuti oleh dokumen baru, pemulihan, atau tidak ada pemulihan sama sekali. Penyiapan dapat berjalan setelah pemuatan awal dan setelah beberapa kali pemulihan, sehingga kedua operasi harus mentoleransi pengulangan.
let liveSocket = null;
function connectLiveUpdates() {
if (liveSocket) return;
liveSocket = new WebSocket("wss://shop.example/live-cart");
}
function disconnectLiveUpdates() {
liveSocket?.close();
liveSocket = null;
}
async function revalidateSensitiveState() {
const response = await fetch("/api/session-snapshot", {
cache: "no-store",
credentials: "same-origin",
});
if (response.status === 401) {
location.replace("/login");
return false;
}
if (!response.ok) {
showRetryState();
return false;
}
renderSessionState(await response.json());
return true;
}
window.addEventListener("pagehide", disconnectLiveUpdates);
window.addEventListener("pageshow", async (event) => {
reportNavigation(event.persisted ? "bfcache_restore" : "document_load");
if (event.persisted && !(await revalidateSensitiveState())) return;
connectLiveUpdates();
});Endpoint server pada contoh tetap menjadi otoritas. UI harus menonaktifkan checkout saat status sensitif yang dipulihkan sedang diperiksa, dan pemeriksaan yang gagal harus menampilkan status coba lagi alih-alih mempercayai snapshot secara diam-diam. Permintaan checkout sisi server tetap harus mengotorisasi ulang pengguna dan menghitung ulang harga serta inventaris.
Jangan gunakan unload untuk pembersihan kritis. Ini tidak dapat diandalkan dan dapat membuat halaman tidak memenuhi syarat di beberapa peramban. Lebih baik gunakan pagehide untuk pembersihan siklus hidup halaman dan gunakan visibilitychange jika persyaratannya adalah visibilitas alih-alih navigasi. Hindari menjadikan freeze dan resume (yang hanya ada di Chromium) sebagai satu-satunya jalur kebenaran.
Langkah 3: Diagnosis miss dari reproduksi lokal hingga kepemilikan
Reproduksi satu rute dengan urutan deterministik: buka langsung, tetapkan status yang relevan, ikuti tautan normal ke dokumen kedua, lalu gunakan tombol Back peramban. Hindari ekstensi dan alat pengembangan dalam proses kontrol karena dapat mengubah perilaku siklus hidup. Ulangi dengan header respons produksi dan skrip pihak ketiga.
Di Chrome, jalankan uji Back/forward cache pada panel Application. Catat apakah hasilnya dapat ditindaklanjuti (actionable), menunggu dukungan peramban, atau tidak dapat ditindaklanjuti, dan perluas atribusi frame. Jika pendengar unload muncul, cari tahu apakah kode pihak pertama atau vendor yang mendaftarkannya. Jika kebijakan respons, koneksi terbuka, transaksi aktif, lock, API media, atau frame muncul, perkecil ke fitur nyata terkecil yang mereproduksi hasil tersebut.
Jika didukung, periksa notRestoredReasons pada dokumen baru yang dicapai melalui penelusuran riwayat yang miss. Pertahankan hierarki dan nilai alasan yang dikembalikan sebagai data diagnostik, bukan logika aplikasi. Jangan melakukan hard-code pada string alasan yang pasti, berasumsi bahwa setiap peramban mengekspos properti tersebut, atau menafsirkan null saja sebagai hit yang dikonfirmasi. Detail turunan lintas-asal dapat disamarkan demi privasi; uji vendor yang disematkan secara terpisah atau hapus dalam eksperimen terkontrol untuk memastikan kausalitas.
Perbaiki satu pemilik pada satu waktu, jalankan kembali pengujian terisolasi, lalu verifikasi seluruh rute. Menutup koneksi IndexedDB atau WebSocket pada pagehide, menghapus handler unload, dan membatasi frame pihak ketiga adalah contoh hipotesis; hasil peramban menentukan apakah perubahan tersebut benar-benar memengaruhi kelayakan.
Langkah 4: Verifikasi kebenaran dan performa di lapangan
Pancarkan satu peristiwa untuk setiap pageshow. persisted: true adalah pemulihan yang dikonfirmasi. Untuk pemuatan dokumen baru, lampirkan jenis Navigation Timing; back_forward mengidentifikasi penelusuran riwayat teramati yang melewatkan bfcache. Buat peristiwa-peristiwa tersebut saling eksklusif. Tambahkan kelompok rute, peramban, versi, status autentikasi, dan kohort eksperimen tanpa mencatat konten halaman privat.
Ukur setidaknya:
- pemulihan yang dikonfirmasi dibagi dengan penelusuran riwayat yang dapat diamati, disegmentasi berdasarkan peramban dan rute;
- jumlah miss dan kelompok alasan pemblokiran yang didukung, termasuk kasus yang disamarkan dan tidak tersedia;
- latensi restore-to-next-paint dan restore-to-interactive-sensitive-state;
- kegagalan validasi ulang sesi, izin, keranjang, harga, dan inventaris;
- upaya checkout yang diblokir saat status yang dipulihkan belum diverifikasi;
- efek samping soket, observer, analitik, dan timer duplikat setelah siklus Back/Forward berulang;
- regresi memori dan kegagalan yang terlihat oleh pengguna, karena memaksimalkan rasio hit bukanlah satu-satunya tujuan.
Jalankan siklus riwayat berulang kali, keluar (sign out) di tab lain, ubah keranjang di tempat lain, buat token sekali pakai kedaluwarsa, gagalkan endpoint validasi ulang, dan jalankan frame lintas-asal. Uji versi Chrome, Firefox, dan Safari yang masuk dalam cakupan. Panel Chrome lokal membuktikan satu kasus terkontrol; telemetri produksi membuktikan distribusi, dan asersi produk membuktikan keamanan.
Contoh jawaban berkualitas tinggi
"Jalur instan adalah bfcache: peramban mempertahankan seluruh dokumen checkout dan JavaScript heap-nya, menjedanya, dan melanjutkannya selama navigasi riwayat sesi. Cache HTTP hanya menyimpan respons, sedangkan router klien menangani navigasi lunak dalam dokumen aktif. Pertama-tama saya akan melabeli jalurnya. pageshow.persisted === true mengonfirmasi pemulihan. Dokumen baru yang jenis Navigation Timing-nya adalah back_forward mewakili penelusuran riwayat yang tidak memulihkan halaman ini dari bfcache. pagehide.persisted === true hanyalah niat peramban untuk menyimpan cache, jadi saya tidak akan menggunakannya sebagai catatan hit."
"Pada pagehide, saya menutup sumber daya yang seharusnya tidak tetap aktif, seperti soket keranjang dan transaksi terbuka apa pun, menggunakan pembersihan idempoten. Pada setiap pageshow, saya memastikan sumber daya terhubung tepat satu kali. Untuk pemulihan yang dikonfirmasi, saya memblokir checkout untuk sementara, mengambil snapshot sesi dan keranjang yang otoritatif, memperbarui UI, dan mengalihkan (redirect) jika logout. API checkout tetap memeriksa otorisasi, harga saat ini, dan inventaris, sehingga heap yang dilanjutkan tidak akan pernah dapat mengotorisasi pembelian. Saya menghitung pemulihan satu kali untuk analitik daripada menjalankan kembali semua efek pemuatan awal."
"Untuk misses, saya mereproduksi jalur dokumen penuh yang persis dengan header produksi dan vendor. Di Chrome saya menjalankan pengujian bfcache di panel Application, memperluas kepemilikan frame, dan memperbaiki penyebab yang dapat ditindaklanjuti satu per satu. Pada versi Chromium yang didukung, saya mengumpulkan notRestoredReasons untuk pemuatan riwayat yang terlewat, mempertahankan kasus yang disamarkan dan tidak diketahui, serta tidak pernah mencabangkan perilaku produk berdasarkan teks alasan. Kemudian saya menguji matriks Chrome, Firefox, dan Safari yang didukung karena kelayakan berubah berdasarkan implementasi dan skenario."
"Gerbang peluncuran adalah rasio pemulihan terkonfirmasi yang lebih tinggi dengan latensi kembali yang lebih rendah, sementara tindakan sesi basi, koneksi ganda, dan duplikasi analitik tetap nol dalam pengujian. Saya mensegmentasi misses dan kegagalan validasi ulang berdasarkan rute dan peramban. Jika kebijakan menyatakan bahwa halaman yang berisi data privat tertentu tidak boleh di-snapshot, saya mempertahankan pembatasan tersebut dan mengoptimalkan halaman-halaman di sekitarnya daripada mengorbankan keamanan demi rasio hit."
Kesalahan umum dan perbaikan
- Menyebut setiap jalur kembali sebagai "cache peramban" → Respons HTTP, snapshot seluruh dokumen, dan status router mematuhi aturan yang berbeda → Sebutkan mekanismenya dan kumpulkan bukti spesifik mekanisme.
- Menggunakan
pageshowsaja sebagai bukti → Peristiwa ini juga terpicu pada pemuatan dokumen awal → Wajibkanevent.persisted === trueuntuk pemulihan yang dikonfirmasi. - Memperlakukan
pagehide.persistedsebagai hit di masa mendatang → Peramban mungkin nantinya akan mengeluarkan halaman tersebut atau memilih jalur lain → Gunakan hanya untuk memandu pembersihan yang aman; catat hit saat pemulihan. - Mengasumsikan
back_forwardberarti bfcache → Ini dapat menggambarkan dokumen baru yang dimuat oleh penelusuran riwayat → Gabungkan jenis navigasi untuk misses denganpageshow.persisteduntuk hit. - Menonaktifkan semua caching untuk memperbaiki UI basi → Ini menyembunyikan bug siklus hidup dan mengorbankan navigasi instan → Validasi ulang bidang sensitif dan pertahankan otorisasi server sebagai hal yang otoritatif.
- Memuat ulang setiap halaman yang dipulihkan → Pemuatan ulang menyeluruh membuang optimasi dan dapat mengalami perulangan (loop) saat gagal → Segarkan hanya status yang otoritatif, cadangkan pemuatan ulang atau pengalihan hanya untuk status tidak valid yang telah ditentukan.
- Menghafal daftar pemblokir permanen → Kelayakan dan nama alasan berubah di berbagai engine dan versi → Gunakan pengujian peramban, deteksi fitur, dan bukti lapangan.
- Menempatkan pembersihan di
unload→ Peristiwa ini tidak dapat diandalkan dan dapat mencegah kelayakan → Gunakanpagehide, ditambah peristiwa visibilitas jika persyaratan produk adalah visibilitas. - Menghubungkan kembali pada setiap peristiwa siklus hidup →
pageshow,resume, dan efek framework dapat membuat soket atau observer duplikat → Berikan setiap sumber daya satu pemilik yang idempoten. - Mempercayai satu kali pemeriksaan DevTools → Ini tidak mencakup vendor nyata, tekanan memori, peramban lain, atau perubahan sesi → Gabungkan pengujian terkontrol, matriks peramban, RUM, dan alur produk yang berlawanan (adversarial).
Pertanyaan lanjutan
Apakah Cache-Control: no-cache memaksa validasi sebelum pemulihan bfcache?
Tidak. Pemulihan bfcache melanjutkan dokumen di memori alih-alih memenuhi permintaan sumber dayanya melalui cache HTTP, sehingga arahan validasi ulang HTTP tidak berjalan sebelum halaman yang dipulihkan ditampilkan. Gunakan pageshow.persisted untuk memicu pemeriksaan kesegaran terarah. Jika kebijakan melarang penyimpanan snapshot halaman sama sekali, terapkan kebijakan respons dan peramban yang sesuai, dengan menerima bahwa kelayakan dapat bervariasi berdasarkan implementasi.
Apakah PerformanceNavigationTiming.type === "back_forward" merupakan sinyal hit?
Tidak. Ini memberi tahu dokumen yang baru dibuat bahwa dokumen tersebut dicapai melalui penelusuran riwayat. Pemulihan bfcache yang dikonfirmasi melanjutkan dokumen yang ada dan diidentifikasi dengan pageshow.persisted === true. Hitung pemuatan back_forward baru sebagai misses yang dapat diamati, tergantung pada keanehan peramban seperti skenario mulai ulang atau tab yang dibuka kembali, dan segmentasikan telemetri sebagaimana mestinya.
Bagaimana jika notRestoredReasons hilang, bernilai null, atau disamarkan?
Perlakukan data yang hilang sebagai tidak didukung, null sebagai data yang tidak cukup jika berdiri sendiri, dan yang disamarkan sebagai kategori diagnostik penjaga privasi. Konfirmasikan hit dengan peristiwa transisi halaman. Untuk misses, reproduksi secara lokal, periksa output DevTools yang tersedia, isolasi frame turunan dan skrip pihak ketiga, dan pertahankan kategori tidak diketahui alih-alih mengarang alasan.
Bagaimana analitik harus menangani halaman yang dipulihkan?
Pilih definisi produk terlebih dahulu. Jika pemulihan dihitung sebagai page view, pancarkan satu peristiwa dari pageshow.persisted dan hindari memutar ulang instrumentasi pemuatan awal. Sertakan kolom jenis navigasi agar analis dapat memisahkan pemuatan dokumen dari pemulihan. Reset akumulator performa dengan cakupan kunjungan jika sesuai, dan uji siklus Back/Forward berulang untuk memastikan tidak ada duplikasi.
Haruskah halaman checkout yang diautentikasi menggunakan bfcache?
Hanya jika kebijakan keamanan mengizinkan snapshot halaman dan jalur pemulihan dapat dibuat aman. Saat pemulihan, validasi ulang sesi dan data penting, blokir tindakan sensitif hingga pemeriksaan selesai, dan pertahankan otorisasi sisi server serta verifikasi harga sebagai kewajiban. Jika konten privat tidak boleh dapat dipulihkan dalam riwayat, tegakkan kebijakan tersebut dan fokuskan optimasi bfcache pada rute yang kurang sensitif.