Soalan
Sebuah aplikasi web desktop mengimport fail-fail besar. Pengguna boleh mengklik untuk memilih fail, menyeret fail ke zon lepas (drop zone), atau menggunakan pelayar yang menyokong showOpenFilePicker(). Reka bentuk aliran frontend yang lengkap, termasuk pengesanan ciri, sandaran (fallback), pembatalan, kemajuan, kebolehcapaian, privasi dan percubaan semula. Terangkan keupayaan mana yang merupakan penambahbaikan dan bukannya kebergantungan garis dasar (baseline).
Jawapan rujukan
Gunakan satu model input: File atau pemegang fail (file handle) yang boleh dibaca. UI sepatutnya hanya menerima fail calon, sumber, saiz, jenis dan keadaan. Garis dasarnya ialah <input type="file"> yang kelihatan dan berlabel kerana ia tersedia secara meluas; seret dan lepas ialah satu lagi cara untuk menghasilkan model yang sama. Jika window.showOpenFilePicker wujud dalam konteks selamat (secure context), gunakannya hanya daripada pengendali klik pengguna sebagai penambahbaikan. Jika pemilih (picker) gagal, dibatalkan, atau kebenaran ditolak, kekalkan laluan input agar sentiasa tersedia daripada menganggap pengecualian tersebut sebagai ketiadaan sokongan.
Modelkan aliran sebagai idle → selected → validating → reading → uploading → complete, dengan cawangan cancelled dan failed. Sahkan sambungan fail (extension), MIME yang diisytiharkan, had saiz sebenar dan format perniagaan; semakan klien memberikan maklum balas pantas, manakala pelayan mesti mengesahkannya semula. Baca fail besar sebagai penstriman (streams) atau hirisan (slices), batalkan pembacaan dan muat naik dengan AbortController, cuba semula hanya ketulan (chunks) yang boleh dimainkan semula, dan tunjukkan bait yang telah selesai berserta anggaran.
Nama, laluan dan kandungan adalah data pengguna. Tunjukkan metadata yang perlu sahaja dan elakkan kandungan daripada log; batalkan URL objek pratonton dengan URL.revokeObjectURL(). Zon lepas memerlukan laluan papan kekunci dan butang biasa, dengan fokus, ralat dan kemajuan didedahkan melalui elemen semantik serta kawasan langsung (live region). Menyeret tidak boleh menjadi satu-satunya operasi. Beritahu pengguna apabila data akan dimuat naik, kemudian bersihkan rujukan tempatan dan kerja yang belum selesai selepas pembatalan.
Kesukaran utama
showOpenFilePicker() memerlukan pengaktifan pengguna sementara (transient user activation), jadi ia tidak boleh dipanggil daripada pemasa (timer), pemuatan halaman, atau tugasan latar belakang yang tertangguh. Ia mengembalikan pemegang (handles), yang tidak membayangkan kebenaran membaca secara kekal. Pengesanan ciri tidak menjamin kebenaran. accept pada input ialah petunjuk, bukan semakan keselamatan, dan File.type mungkin kosong atau dibekalkan oleh klien. Pengendali pelepasan (drop handlers) mesti menghalang navigasi lalai dan mengendalikan direktori, berbilang fail serta senarai yang sangat besar.
Kesilapan lazim
- Menganggap File System Access API sebagai kebergantungan garis dasar.
- Mempercayai sambungan fail atau nilai MIME sebagai pengesahan keselamatan fail.
- Menyembunyikan input tanpa mengekalkan label, laluan papan kekunci dan laluan pembaca skrin.
- Membaca keseluruhan fail besar ke dalam memori sebelum memuat naik.
- Menunjukkan "kebenaran ditolak" untuk pembatalan, ralat format dan kegagalan rangkaian secara sama rata.
Analisis pertukaran (trade-off)
Input ialah garis dasar yang boleh dipercayai dengan capaian paling luas, tetapi ia tiada operasi peringkat pemegang. Pemilih boleh mengurangkan pemilihan berulang dan mendedahkan operasi pemegang yang lebih kaya, namun bergantung pada sokongan pelayar, HTTPS, pengaktifan pengguna dan kebenaran. Seret dan lepas meningkatkan daya pemprosesan (throughput) desktop tetapi memerlukan alternatif papan kekunci. Pengesahan klien memendekkan masa maklum balas; pengesahan pelayan ialah sempadan keselamatan. Pemecahan ketulan (chunking) dan keupayaan menyambung semula menambah kerumitan keadaan tetapi mengurangkan kos mencuba semula pemindahan fail yang besar.
Contoh yang boleh dijalankan
async function chooseFiles(input) {
if (window.showOpenFilePicker && window.isSecureContext) {
try {
const handles = await window.showOpenFilePicker({ multiple: true });
return Promise.all(handles.map((handle) => handle.getFile()));
} catch (error) {
if (error?.name !== "AbortError") throw error;
}
}
return Array.from(input.files ?? []);
}Panggil ini daripada pengendali klik pengguna. Kod pengeluaran juga harus mengekang jenis, bilangan dan saiz serta memetakan kegagalan kepada keadaan yang dihadapi pengguna. Pengendali pelepasan boleh menukar event.dataTransfer.files kepada tatasusunan yang sama dan menggunakan semula mesin keadaan pengesahan serta muat naik.
Soalan susulan penemu duga
Mengapa tidak memanggil showOpenFilePicker() semasa pemuatan halaman? API memerlukan pengaktifan pengguna sementara, jadi panggilan yang tertangguh atau di latar belakang boleh ditolak. Adakah accept menghalang perisian hasad (malware)? Tidak. Ia hanyalah petunjuk pemilih; semakan keselamatan adalah tanggungjawab pada pelayan. Mengapa perlu mengekalkan sandaran (fallback)? Sokongan pelayar dan kebenaran boleh berbeza-beza, jadi garis dasar mesti berfungsi dengan input yang tersedia secara meluas.
Respons susulan
Bagaimanakah anda menguji laluan sandaran (fallback)?
Uji pelayar yang tidak disokong, konteks tidak selamat, pembatalan dan kebenaran yang ditolak secara berasingan; pastikan (assert) bahawa laluan input masih dapat menyelesaikan import.
Bagaimanakah anda mengelakkan kehabisan memori?
Gunakan File.slice() atau penstriman (streams), hadkan keserentakan (concurrency), muat naik ketulan (chunks) dan batalkan pengawal (abort controller) apabila pengguna membatalkan operasi.
Bagaimanakah anda menjadikan aliran ini mudah diakses?
Kekalkan label dan butang sebenar, jadikan zon lepas boleh difokuskan, benarkan papan kekunci mencetuskan input, dan kaitkan ralat serta kemajuan dengan teks dan kawasan langsung (live region).
Metrik manakah yang menunjukkan bahawa ia berfungsi?
Jejak kejayaan, pembatalan, kegagalan pengesahan, penyelesaian akhirnya selepas percubaan semula, masa untuk mencapai kemajuan pertama dan kadar sandaran mengikut pelayar tanpa merekodkan kandungan fail.