JavaScript 動態 import() 失敗怎麼重試?Chrome 155 Beta 的模組載入邊界
使用 JavaScript 程式碼分割時,常見寫法是由互動事件觸發 import('./feature.js')。如果使用者剛好遇到網路中斷、暫時性的 CDN 錯誤或部署切換,第一次載入可能失敗;在部分瀏覽器行為中,失敗結果會被快取,第二次呼叫 import() 只會立即失敗,重新連線也無法補救。
Chrome for Developers 在 2026 年 9 月 16 日的 Chrome 155 Beta 公告說明,模組載入失敗後可以手動重試,例如再次呼叫 import()。這是 Beta channel 的瀏覽器行為更新,不是可以假設所有瀏覽器都已支援的新 JavaScript API;產品仍應自己控制重試次數、錯誤 UI 和 fallback。
先確認失敗真的值得重試
重試適合處理「可能短暫恢復」的失敗,不適合掩蓋部署錯誤。可以先把原因分成三類:
| 類型 | 例子 | 建議 |
|---|---|---|
| 暫時性網路問題 | 連線中斷、行動網路切換、CDN 短暫逾時 | 延遲後有限重試 |
| 版本切換問題 | HTML 是新版本,但 chunk 仍來自舊快取 | 重新取得入口或顯示重新整理提示 |
| 確定性錯誤 | 404、語法錯誤、CSP 或權限阻擋 | 優先修部署或設定,不要無限重試 |
import() 的 rejection 通常不會提供一個足以準確分類所有原因的跨瀏覽器錯誤型別。要判斷是否值得重試,應搭配網路請求紀錄、CDN/伺服器狀態與前端錯誤監控,而不是看到 TypeError 就一律再試。
用 wrapper 控制次數與等待時間
可以把載入函式包起來,讓每個 feature 自己保留相同的重試規則:
function wait(milliseconds) { return new Promise((resolve) => setTimeout(resolve, milliseconds));}
async function importWithRetry(load, { attempts = 2, delayMs = 250 } = {}) { let lastError;
for (let attempt = 0; attempt < attempts; attempt += 1) { try { return await load(); } catch (error) { lastError = error; if (attempt === attempts - 1) throw error; await wait(delayMs); } }
throw lastError;}
const feature = await importWithRetry(() => import('./feature.js'));feature.start();這是文章中的示意範本,沒有在本機瀏覽器執行。attempts = 2 代表最多一次初始載入加一次重試,不是要把次數設得越大越好。若失敗原因是 chunk 不存在或程式碼有語法錯誤,重試只會增加等待時間。
Chrome 155 Beta 的改變在哪裡
Chrome 官方描述的問題是:過去失敗的 module load 會被快取,後續重試只會立即失敗;Chrome 155 Beta 讓開發者可以手動重試失敗的模組載入,例如再次呼叫 import()。因此,對可恢復的網路錯誤而言,上面的 wrapper 在新行為下才有機會真的重新取得模組。
這不代表可以把 wrapper 當成瀏覽器支援偵測:
import()本身在不同瀏覽器都可能失敗,但失敗後是否可重新取得模組的行為不一致。- 沒有必要為了「強迫重試」就隨機修改 module specifier;加入 query string 會改變模組識別,可能造成重複載入和 singleton 狀態分裂。
- 如果產品不能鎖定 Chrome Beta,請把 retry 視為漸進式改善,並保留重新整理、離線提示或預先打包的 fallback。
若你的載入流程同時包含 API 請求,請將模組載入重試和請求 timeout 分開設計;可參考 AbortSignal.timeout() 的請求逾時處理,不要把一次 API 失敗和 chunk 載入失敗混成同一個計數器。
版本切換時不要只靠重試
前端部署常見的另一種錯誤是:使用者手上的 HTML 指向新 chunk,但 service worker、瀏覽器或 CDN 還保留舊版本。這時可以搭配版本策略處理:
- 在 HTML 或執行期保留目前前端版本識別,收到 chunk 載入錯誤時記錄它。
- 第一次重試前先確認網路請求是否真的恢復,不要在短時間內連續打同一個失效 URL。
- 若同一版本連續失敗,顯示「重新整理以取得最新版本」的可操作訊息。
- 只有在確認部署能提供該 chunk 時,才把錯誤歸類成暫時性載入問題。
重新整理不是萬靈丹:如果 CDN 仍在部署或新版本本身缺少檔案,重整只會重新遇到相同錯誤。錯誤事件要包含 chunk URL、前端版本、網路狀態與重試次數,才能與部署紀錄對照。
生產環境的最小檢查表
- 設定全域上限,例如一次初始載入加一次重試,不要讓每個元件無限迴圈。
- 只對可能暫時性的錯誤延遲重試;404、解析錯誤與 policy 阻擋要直接進 fallback。
- 對 retry、最終失敗、重新整理點擊分開記錄,避免只看到「載入失敗」而無法判斷改善效果。
- 在 Chrome Beta 與主要穩定版瀏覽器各測一次,確認舊環境仍能顯示可操作的錯誤訊息。
- 對 lazy-loaded 路由、互動元件與背景預載分別設定策略,不要共用一個不透明的全域重試器。
Q: 只要在 import() 外面加 retry,就能支援所有瀏覽器嗎?
A: 不能。Chrome 155 Beta 公告描述的是失敗 module load 的快取行為改變;其他瀏覽器可能仍快取失敗結果。請保留重新整理或替代 UI,並在實際支援矩陣中驗證。
Q: 可以用隨機 query string 強制瀏覽器重新載入 module 嗎?
A: 技術上會改變 module specifier,但不應把它當成預設方案。它可能造成同一模組被載入多份,破壞 singleton 或共用狀態;先修正部署、CDN 與版本策略,再決定是否有明確的 cache-busting 需求。
Q: 遇到 404 的 dynamic import 也要重試嗎?
A: 通常不值得。404 多半表示 chunk 沒有部署、URL 版本不一致或路由設定錯誤,應記錄版本與 URL 並修正部署;無限重試只會延遲錯誤回饋。
參考資料: