網頁功能:
頂層 await
頂層 await 可讓模組做為非同步函式,也就是說,模組可以暫停執行,等待 Promise。這項功能非常實用,可讓您在瀏覽器需要時,才載入非同步依附元件 (例如 polyfill 或大型次要程式庫)。
只要使用頂層 await,就能將條件式載入邏輯封裝在單一模組中,有效防止下游消費者模組在依附元件完全載入並準備就緒前執行。
條件式 Polyfill 模式
雖然頂層 await 可用於有條件地載入任何模組的非同步依附元件,但條件式依附元件載入模式的良好用途,是有條件地載入不支援特定功能的瀏覽器 polyfill。這個方法會將功能偵測和動態匯入封裝在單一依附元件模組中。
在以下情況中,如果 HTMLElement.prototype 沒有 popover 屬性,系統會視情況載入該屬性的 polyfill:
// conditionally-load-polyfill.js
// Check if the feature is missing before doing work.
// MANDATORY: Prefer checking HTMLElement.prototype over window or document
// when checking for a global DOM attribute or property like popover.
if (!('popover' in HTMLElement.prototype)) {
// Use top-level await to pause the execution of any module that imports this file
// until the polyfill finishes downloading and executing.
await import('/path/to/popover-polyfill.js');
}
// Export a marker if needed by your application
export const polyfillLoaded = true;
// main.js
// MANDATORY: Because conditionally-load-polyfill.js uses top-level await,
// this import will block execution of main.js until the polyfill is ready.
import './conditionally-load-polyfill.js';
// Now it is safe to use the feature (e.g., showing a popover)
const myPopover = document.getElementById('my-popover');
if (myPopover) {
myPopover.showPopover();
}
排序模組匯入作業,並避免 Safari 27 之前的錯誤
必要:您必須建構模組圖,讓頂層 await 模組從單一進入點匯入,並在下游模組評估前完成:
- 請勿在項目檔案中放置同層靜態匯入 (例如
import './conditionally-load-polyfill.js'; import './app.js';)。根據 ECMAScript 模組評估規格,頂層await只會暫停匯入該模組的父項模組,而不會暫停同層靜態匯入,因此./app.js會在所有瀏覽器中同時評估,直到 polyfill 載入完成。 - 請勿同時從多個同層模組匯入頂層
await模組 (例如讓a.js和b.js都靜態匯入./conditionally-load-polyfill.js)。雖然 Safari 27 已修正 WebKit 的模組載入器,可依規格同時匯入頂層await模組,但 Safari 15 至 26.6 在多個模組同時匯入含有頂層await的模組時會失敗 (請參閱 MDN 瀏覽器相容性)。
請改為根據模組結構,選擇下列其中一種模式:
- 單一進入模組 (如上方的
main.js所示):如果進入模組直接執行依附元件初始化邏輯,請在該模組頂端靜態匯入./conditionally-load-polyfill.js,並在主體中執行程式碼。 - 啟動獨立應用程式模組:如果您的進入模組委派給下游應用程式模組 (例如
./app.js),請使用頂層await鏈結動態import()呼叫,這樣系統只會在 Polyfill 模組解析後擷取及評估./app.js:
// main.js
// MANDATORY: Chain dynamic imports with top-level await when bootstrapping separate
// application modules so './app.js' waits for the polyfill to finish loading.
// DO NOT use sibling static imports (`import './conditionally-load-polyfill.js'; import './app.js';`),
// which evaluate concurrently and execute './app.js' before the polyfill is ready.
await import('./conditionally-load-polyfill.js');
await import('./app.js');
備用策略
雖然自 2021 年起,各大瀏覽器 (Chrome 89、Edge 89、Firefox 89 和 Safari 15) 都支援基本的頂層 await,但直到 Safari 27 才完全符合規格 (請參閱 MDN 瀏覽器相容性)。
- Safari 15–26.6:只要遵循上一節的單一進入點模式,讓多個同層模組不會同時匯入頂層
await模組,就能安全地依賴頂層await,不需額外的備用方案。 - 舊版瀏覽器 (2021 年前):如果應用程式必須支援不支援頂層
await的瀏覽器,請避免使用頂層await,並將條件式import()協調包裝在標準async函式或.then()承諾鏈中。