前端面試:設計漸進增強的檔案匯入流程
題目
桌面 Web 應用需要匯入大檔案,使用者可以點擊選擇、拖放檔案,也可能使用支援 showOpenFilePicker() 的瀏覽器。請設計完整的前端匯入流程:特性偵測、回退、取消、進度、無障礙、隱私和失敗重試都要考慮。說明哪些能力只能作為增強,不能作為基礎依賴。
參考答案
先把統一輸入模型定義為 File 或可讀取的檔案控制代碼,UI 層只接收「候選檔案、來源、大小、類型、狀態」。預設路徑使用帶可見 label 的 <input type="file">,因為它跨瀏覽器可用;拖放只是同一輸入模型的另一個入口。偵測到 window.showOpenFilePicker 且執行在安全內容時,再由使用者點擊按鈕觸發增強路徑。增強路徑失敗、使用者取消或權限被拒絕時,保留選擇入口並回退到 input,而不是把例外當成不支援。
匯入狀態可設為 idle → selected → validating → reading → uploading → complete,並有 cancelled、failed 分支。驗證檔案副檔名、宣告的 MIME、實際大小上限和業務格式;前端驗證只用於即時回饋,伺服器仍須重新驗證。大檔案按串流或分片讀取,使用 AbortController 取消讀取與上傳,重試只重試可安全重放的分片,並顯示已完成位元組數與剩餘估計。
檔名、路徑和內容屬於使用者資料。介面只展示必要中繼資料,日誌不記錄內容;預覽用完的 object URL 要 revokeObjectURL()。拖放區必須支援鍵盤和一般按鈕,焦點、錯誤文字和進度透過語意元素及 live region 告知;不要把拖放作為唯一操作。提交前明確告知何時會上傳,使用者取消後清理本地引用和未完成任務。
關鍵難點
showOpenFilePicker() 需要瞬時使用者啟用,不能在計時器、頁面載入或非同步鏈路後偷偷呼叫;它回傳控制代碼,不等同於已取得永久讀取權限。特性偵測也不代表權限一定成功。input 的 accept 是提示,不是安全驗證;File.type 也可能為空或由用戶端宣告。拖放事件要防止預設導覽行為,並處理目錄、多檔案和超大清單。
常見誤區
- 把 File System Access API 當成所有瀏覽器的基礎能力。
- 只檢查副檔名或 MIME 就信任檔案。
- 讓隱藏 input 失去 label、鍵盤和螢幕閱讀器路徑。
- 讀取整個大檔案到記憶體,再一次上傳。
- 用「權限被拒絕」覆蓋使用者取消、格式錯誤和網路失敗。
取捨分析
統一使用 input 作為可靠基線,覆蓋面最好但無法提供控制代碼級能力;增強 picker 可減少重複選擇並支援更細的控制代碼操作,卻受瀏覽器、HTTPS、使用者啟用和權限約束。拖放提升桌面效率,卻需要額外的鍵盤替代路徑。用戶端預先驗證能縮短回饋時間,伺服器驗證才能形成安全邊界。分片與斷點續傳增加狀態複雜度,但能降低大檔案失敗重傳成本。
可執行範例
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 ?? []);
}呼叫必須直接來自使用者點擊事件;正式程式還應限制類型、數量和大小,並把例外映射為使用者可理解的狀態。拖放處理器可以把 event.dataTransfer.files 轉成相同陣列,再走同一驗證和上傳狀態機。
面試官可能追問
為什麼不能在頁面載入時直接呼叫 showOpenFilePicker()?因為規範要求瞬時使用者啟用,非同步或背景呼叫會被瀏覽器拒絕。accept 能防毒嗎?不能,它只是選擇器提示,安全檢查必須在伺服器完成。為什麼需要回退?瀏覽器支援和權限會變化,基礎流程必須在廣泛可用的 input 上成立。
追問及應對
如何測試回退路徑?
用不支援該 API 的瀏覽器、非安全內容、使用者取消和權限拒絕分別測試;斷言 UI 仍能透過 input 完成匯入。
如何避免大檔案佔滿記憶體?
使用 File.slice() 或串流讀取,限制並行,以上傳分片並在取消時呼叫 AbortController。
如何保證無障礙?
保留真實 label 和按鈕,拖放區可聚焦,鍵盤可觸發 input,錯誤與進度使用關聯文字和 live region。
哪些指標能證明設計有效?
記錄各入口成功率、取消率、驗證失敗率、重試後完成率、首次進度回饋時間和不同瀏覽器的回退比例,且不記錄檔案內容。