Perintah dan cakupan
Anda harus mengunggah berkas besar dan menghitung digest di peramban. Peramban baru mendukung Blob.bytes(), tetapi peramban lama mungkin tidak. Rancang pembacaan, pemotongan (chunking), fallback, pembatalan, penanganan kesalahan, dan validasi kompatibilitas.
MDN menandai Blob.bytes() sebagai Baseline 2026: metode ini mengembalikan Promise yang diselesaikan ke Uint8Array yang berisi data Blob dan tersedia di Web Workers. Wawancara ini menguji semantik API dan batas sumber daya; sekadar mendukung metode baru bukanlah desain pengunggahan yang lengkap.
Apa yang dievaluasi oleh pewawancara
- Menjelaskan hasil Promise dan
Uint8Arraysecara akurat tanpa menyebutnya sebagai stream. - Mengenali lonjakan memori akibat membaca seluruh Blob dan merancang potongan (chunks) atau jalur stream.
- Menggunakan deteksi fitur dengan fallback
arrayBuffer()ataustream()alih-alih pemeriksaan nama peramban. - Menangani pembatalan, percobaan ulang (retries), status digest, pengiriman pesan worker, dan umpan balik pengguna.
- Membuktikan desain dengan matriks kompatibilitas dan uji stres berkas besar.
Pertanyaan klarifikasi
- Berapa batas ukuran berkas, konkurensi pengunggahan, peramban target, dan ketersediaan Worker?
- Algoritma digest, protokol potongan server, semantik pelanjutan (resume), dan kebijakan potongan duplikat apa yang berlaku?
- Apakah digest lengkap harus ada sebelum pengunggahan, atau dapatkah klien mengunggah sambil membaca dan memverifikasinya di akhir?
- Bisakah transfer yang gagal dilanjutkan dari potongan yang telah dikonfirmasi, dan bagaimana idempotensi server didefinisikan?
- Apa yang terjadi ketika pengguna berpindah halaman, menutup tab, atau perangkat berada di bawah tekanan memori?
Semantik API dan jalur pembacaan
Blob.bytes() tidak menerima argumen dan mengembalikan Promise. Nilai yang dipenuhi adalah Uint8Array; kegagalan pembacaan akan menolak Promise tersebut. Metode ini menyerahkan isi Blob kepada pemanggil sebagai satu larik bita (byte array), sehingga tidak membuktikan perilaku zero-copy atau kapasitas berkas besar tanpa batas. Baca berkas kecil di Worker jika bermanfaat; untuk berkas besar, lebih disukai memotong dengan slice() yang diikuti oleh pembacaan dan pengunggahan per potongan.
Deteksi fitur pada jalur: gunakan bytes() jika tersedia, jika tidak gunakan arrayBuffer() dan buat Uint8Array; jika peramban dan protokol mendukungnya, konsumsi stream() secara bertahap (inkremental). Fallback harus mempertahankan penomoran potongan, input digest, dan kontrak kesalahan sehingga validasi server tidak berubah seiring perubahan API.
Memori, potongan, dan digest
Membaca seluruh Blob menciptakan lonjakan memori setidaknya sebesar ukuran berkas, ditambah buffer pengunggahan, decoding, dan overhead runtime. Panggil slice(start, end) dengan batas tetap atau adaptif dan pertahankan hanya potongan saat ini serta antrean pengunggahan yang terbatas. Masukkan ke digest sesuai urutan berkas; pengunggahan paralel tidak boleh mengubah urutan input digest.
Setiap potongan membawa ID berkas, versi, indeks, panjang, dan digest konten. Server menyimpannya secara idempoten berdasarkan ID berkas dan indeks, lalu menyusunnya secara berurutan serta memverifikasi panjang total dan digest seluruh berkas. Digest potongan tidak menggantikan digest menyeluruh (end-to-end) karena kehilangan data, pengurutan ulang, atau penggabungan yang salah masih dapat menghasilkan berkas yang keliru.
Pembatalan, percobaan ulang, dan workers
Kirim sinyal AbortController ke pembacaan dan permintaan pengunggahan; pembatalan akan membersihkan potongan yang mengantre dan melepaskan referensi. Coba lagi hanya pada kesalahan yang dapat dipulihkan dengan backoff eksponensial dan kunci potongan yang idempoten. Kedaluwarsa autentikasi harus dijeda untuk reotorisasi, bukan mencoba ulang terus-menerus. Jika Worker menghitung digest, thread utama menerima progres, kesalahan, dan hasil akhir alih-alih menyalin kembali seluruh larik bita.
Dengan stream(), perhatikan backpressure: pembaca tidak boleh melebihi kecepatan jaringan dan konsumen digest. Setiap jalur mencatat potongan yang dikonfirmasi, durasi pembacaan dan pengunggahan, percobaan ulang, alasan pembatalan, dan perkiraan lonjakan memori, tanpa mencatat konten berkas atau jalur sensitif ke log.
Kompatibilitas dan batas keamanan
Deteksi fitur dapat memeriksa typeof Blob !== "undefined" dan "bytes" in Blob.prototype sebelum memilih bytes(). Jangan hanya bergantung pada User-Agent. Peramban lama dapat beralih ke arrayBuffer() atau FileReader yang terkendali, dan harus menerima pesan yang jelas ketika anggaran memori tidak dapat dipenuhi.
Digest klien memberikan bukti integritas, bukan otorisasi, pemindaian malware, atau validasi tipe konten. Server harus membatasi ukuran berkas, ukuran potongan, rentang indeks, dan durasi total; tipe MIME dari klien bukanlah keputusan keamanan. Hindari menyalin data sensitif lintas worker dan lepaskan referensi segera setelah selesai.
Simulasi kegagalan dan daftar periksa validasi
Cakup peramban dengan dan tanpa bytes(), jalur Worker dan thread utama, berkas kosong, berkas satu potongan dan banyak potongan, berkas sangat besar, gangguan jaringan, pembatalan-dan-pelanjutan, potongan duplikat, potongan tidak berurutan, dan ketidakcocokan digest. Uji stres mencatat waktu baca p95, throughput pengunggahan, lonjakan memori, long task, tingkat kegagalan, dan waktu pemulihan.
Jika bytes() ditolak, pertahankan status potongan dan beralihlah ke fallback eksplisit. Jika fallback melebihi anggaran memori, hentikan dengan pesan langkah berikutnya alih-alih memaksakan pembacaan penuh. Jika server mendeteksi ketidakcocokan digest potongan atau berkas penuh, buang susunan yang belum dikonfirmasi dan lanjutkan dari potongan konsisten terakhir.
Pertanyaan lanjutan dan jawaban referensi
Bagaimana Anda memilih antara bytes() dan arrayBuffer()?
Keduanya dapat memuat seluruh Blob ke dalam memori. bytes() secara langsung menyediakan Uint8Array, yang berguna untuk kode berorientasi bita, tetapi tidak secara otomatis menyediakan streaming. Berkas besar harus menggunakan potongan atau jalur stream.
Mengapa digest seluruh berkas yang hanya dihitung di klien tidak mencukupi?
Metode tersebut tidak dapat membuktikan bahwa server menerima setiap potongan secara berurutan, dan tidak menggantikan pemeriksaan otorisasi atau keamanan konten. Verifikasi indeks potongan, digest potongan, panjang total, dan digest akhir dari server.
Bagaimana Anda memvalidasi fallback untuk peramban lama?
Paksa kedua jalur kemampuan dengan deteksi fitur, lalu uji matriks peramban nyata, eksekusi Worker dan thread utama, tekanan memori, pemulihan offline, dan pembatalan. Satu peramban modern saja tidak cukup.