Gesaan dan latar keadaan
Anda bertanggungjawab ke atas borang permohonan berbilang langkah. Pengguna menukar tab, mengunci telefon, menavigasi ke belakang, atau meninggalkan halaman selama berjam-jam. Pelayar mungkin membekukan halaman, memulihkannya daripada bfcache, atau membuangnya akibat kekangan memori. Borang tersebut mesti memulihkan draf tanpa menimpa data pelayan yang lebih baharu.
Andaikan borang tersebut mengandungi data sensitif tetapi tidak dikawal selia, pengguna boleh log masuk pada beberapa peranti, dan akses rangkaian adalah terputus-putus. Jawapan mestilah menyatakan perkara yang merupakan usaha terbaik (best effort) dan perkara yang berautoriti (authoritative).
Perkara yang diuji oleh penemu bual
- Sama ada anda membezakan antara kebolehlihatan (visibility), pembekuan (freezing), pembuangan halaman (page discard), dan pemulihan bfcache.
- Sama ada anda mengelak daripada menganggap
unloadataubeforeunloadsebagai cangkuk ketahanan (persistence hook) yang boleh dipercayai. - Sama ada draf setempat mempunyai peraturan pemilikan, versi, luput, dan konflik.
- Sama ada pemulihan mengekalkan niat pengguna tanpa menggantikan data pelayan yang lebih baharu secara senyap.
Soalan penjelasan sebelum menjawab
- Adakah kehilangan draf setempat boleh diterima, atau adakah produk mesti menyediakan jaminan pemulihan yang tahan lama? Ini menentukan sama ada storan setempat adalah satu kemudahan atau sekadar cache sahaja.
- Bolehkah draf yang sama disunting pada beberapa peranti? Jika ya, pelayan memerlukan dasar versi atau konflik.
- Adakah data selamat untuk disimpan secara setempat? Medan sensitif mungkin memerlukan penyulitan, peninggalan terpilih, atau tiada penyimpanan setempat langsung.
- Apakah kontrak penyerahan (submit)? Penyimpanan draf dan penyerahan akhir memerlukan peraturan keidempotensian (idempotency) dan pengesahan yang berbeza.
Kerangka jawapan 30 saat
“Saya menganggap pelayan sebagai pihak yang berautoriti dan draf setempat sebagai cache pemulihan yang terhad. Saya mengekalkan draf berversi pada perubahan input dengan debounce, dan melakukan flush kemas kini usaha terbaik (best-effort) apabila dokumen menjadi tersembunyi. Saya menggunakan pageshow untuk mengesahkan semula selepas pemulihan bfcache dan resume untuk menyegarkan keadaan lapuk selepas pembekuan. Saya tidak pernah bergantung pada unload. Setiap draf merekodkan tarikh luput, versi skema, versi asas pelayan, dan medan kotor (dirty fields); konflik ditunjukkan atau digabungkan secara eksplisit dan bukannya ditimpa secara senyap.”
Perincian langkah demi langkah
1. Modelkan keadaan kitaran hayat
visibilitychange memberitahu halaman bahawa ia telah menjadi tersembunyi atau kelihatan; ia tidak menjamin bahawa JavaScript akan terus berjalan. Pelayar boleh membekukan halaman yang tersembunyi, dan halaman yang dibuang mungkin tidak akan menjalankan kod pembersihan sama sekali. pagehide dan pageshow menerangkan navigasi dan pemulihan bfcache, manakala freeze dan resume mendedahkan peralihan kitaran hayat Chromium.
Oleh itu, reka bentuk ini menyimpan data sebelum timbulnya risiko, bukan semasa unload pada saat-saat akhir. Pada visibilitychange kepada hidden, jadualkan penulisan setempat yang kecil dan flush rangkaian secara usaha terbaik. Pada pagehide, hentikan kerja yang tidak penting dan rekodkan titik semak (checkpoint) setempat. Pada pageshow, semak event.persisted dan sahkan semula versi pelayan sebelum memaparkan borang yang dipulihkan.
2. Jadikan draf setempat terhad dan berversi
Simpan hanya medan yang selamat untuk dipulihkan. Rekod draf boleh mengandungi:
draft_id, user_id, form_schema, base_server_version,
changed_at, expires_at, dirty_fields, valuesGunakan IndexedDB untuk data berstruktur dan indeks setempat yang kecil untuk carian. Lakukan debounce pada penulisan supaya menaip tidak menghasilkan penulisan bagi setiap ketukan kekunci, hadkan saiz muatan (payload), dan padamkan draf yang telah luput. Versi skema membolehkan aplikasi memindahkan atau membuang rekod yang tidak serasi daripada menghuraikannya sebagai data semasa.
Rekod setempat bukanlah satu autoriti. Ia merupakan cache peranti pengguna yang mungkin hilang, lapuk, pendua, atau dipadamkan oleh pelayar.
3. Flush dengan selamat apabila halaman menjadi tersembunyi
Apabila dokumen menjadi tersembunyi, komit titik semak setempat terlebih dahulu, kemudian cuba permintaan kecil yang disahkan jika produk menyokong penyimpanan latar belakang. Permintaan itu membawa ID draf dan versi pelayan yang menjadi asasnya. Pelayan menerimanya hanya jika versinya sepadan, kemudian mengembalikan versi baharu.
Jangan sekat navigasi dengan permintaan yang panjang. Jika permintaan tidak dapat diselesaikan, titik semak setempat masih melindungi peranti ini. Elakkan permintaan unload yang segerak: ia memudaratkan navigasi dan tidak dijamin pada laluan kitaran hayat mudah alih.
4. Pulihkan selepas bfcache dan pembekuan (freeze)
Apabila pageshow dicetuskan dengan persisted, halaman mungkin mengandungi snapshot yang lengkap secara visual tetapi lama secara logik. Dapatkan versi pelayan semasa, bandingkannya dengan versi asas borang, dan tunjukkan pilihan konflik jika peranti lain telah menukar draf tersebut. Apabila resume dicetuskan, segarkan sesi dan data yang mungkin telah luput semasa halaman dibekukan.
Jika halaman telah dibuang, tiada keadaan dalam memori untuk disambung semula. Pada pemuatan seterusnya, cari draf setempat yang belum luput, bandingkan versi asasnya dengan pelayan, dan tawarkan pilihan pulihkan, buang, atau gabung. Pengguna harus melihat nilai mana yang lebih baharu sebelum menerima penggabungan.
5. Uji laluan kegagalan dan privasi
Uji pertukaran tab, pertukaran aplikasi mudah alih, navigasi ke belakang/ke hadapan, pemulihan bfcache, pembuangan oleh pelayar, suntingan luar talian, kehabisan kuota, migrasi skema, draf yang luput, dan konflik dua peranti. Pastikan bahawa versi pelayan yang lebih baharu tidak sekali-kali ditimpa secara senyap.
Padamkan (redact) medan sensitif daripada log. Kosongkan draf apabila akaun dipadamkan, patuhi tempoh pengekalan yang singkat, dan terangkan pemulihan setempat dalam notis privasi. Ukur kejayaan pemulihan, kadar konflik, kegagalan penulisan setempat, dan kependaman simpanan pelayan; penunjuk "disimpan" mesti mewakili titik semak yang diketahui, bukan harapan bahawa pengendali unload telah dijalankan.
Contoh jawapan berkualiti tinggi
Saya akan menjadikan pelayan sebagai punca kebenaran (source of truth) berversi dan menyimpan draf setempat yang terhad untuk pemulihan. Perubahan input didebounce ke dalam IndexedDB dengan versi skema, tarikh luput, set medan kotor, dan versi pelayan yang digunakan sebagai asas. Apabila visibilitychange melaporkan tersembunyi, saya menulis titik semak dan mencuba penyimpanan kecil yang disahkan, tetapi saya tidak menyekat navigasi atau bergantung pada unload.
Pada pageshow, terutamanya apabila peristiwa itu datang daripada bfcache, saya mengambil semula versi pelayan sebelum mempercayai borang yang dipulihkan. Pada resume, saya menyegarkan data dan keadaan sesi yang mungkin telah luput semasa dibekukan. Halaman yang dibuang bermula daripada pemuatan baharu dan menawarkan draf setempat yang belum luput. Jika versi berbeza, saya menunjukkan UI konflik atau gabungan peringkat medan; saya tidak pernah menimpa salinan pelayan yang lebih baharu secara senyap. Ujian meliputi pembuangan mudah alih, suntingan luar talian, had kuota, dan konflik dua peranti.
Kesilapan lazim
- Kesilapan: Menyimpan hanya dalam
beforeunload→ Sebab ia gagal: pelayar mudah alih boleh menamatkan halaman tanpa mencetuskannya dan ia boleh menyekat bfcache → Penyelesaian: cipta titik semak pada input dan peralihan tersembunyi. - Kesilapan: Menganggap halaman bfcache yang kelihatan sebagai halaman baharu → Sebab ia gagal: snapshot boleh mengandungi keadaan pelayan yang lapuk → Penyelesaian: sahkan semula pada
pageshowdan bandingkan versi. - Kesilapan: Menjadikan storan setempat sebagai autoriti → Sebab ia gagal: ia boleh dipadamkan, menjadi lapuk, atau tidak tersedia → Penyelesaian: gunakan versi pelayan dan bentangkan data setempat sebagai calon pemulihan.
- Kesilapan: Mencuba semula keseluruhan borang ke atas versi yang lebih baharu → Sebab ia gagal: ia menimpa suntingan yang tidak berkaitan → Penyelesaian: hantar medan kotor dengan versi optimistik dan selesaikan konflik.
- Kesilapan: Merekodkan nilai draf ke dalam log untuk penyahpepijatan → Sebab ia gagal: kandungan sensitif bocor ke dalam telemetri → Penyelesaian: log ID, versi, saiz, dan hasil sahaja.
Soalan susulan dan jawapan
Patutkah saya menggunakan localStorage atau IndexedDB?
Gunakan localStorage hanya untuk metadata segerak yang sangat kecil. IndexedDB sesuai untuk draf berstruktur, muatan yang lebih besar, dan penulisan tak segerak. Kedua-duanya tidak memberikan ketahanan atau autoriti merentas peranti; kedua-duanya memerlukan pengurusan tarikh luput, pengendalian kuota, pemversian skema, dan peraturan privasi.
Bagaimana jika pengguna membuat suntingan luar talian pada dua peranti?
Berikan setiap simpanan versi asas pelayan dan ID peranti atau draf. Apabila sambungan pulih, terima versi yang sepadan sahaja, kemudian tunjukkan gabungan peringkat medan atau biarkan pengguna memilih. Dasar last-write-wins hanya boleh diterima apabila produk menerima kehilangan data secara senyap secara eksplisit dan medan-medan tersebut adalah bebas antara satu sama lain.
Bolehkah service worker menjamin penyimpanan akhir?
Tidak. Service worker boleh menambah baik penghantaran percubaan semula, tetapi ia boleh dihentikan, kehilangan akses rangkaian, atau tidak tersedia dalam aliran tertentu. UI mesti melaporkan titik semak yang disahkan, dan pelayan mesti menjadikan percubaan semula itu bersifat idempoten. Draf setempat kekal sebagai sandaran (fallback) bagi peranti yang tidak dapat menyelesaikan permintaan tersebut.