如何動態導入 ECMAScript 模塊

ES 模塊系統有 2 個角色:

  1. 導入 - import {func} from './myModule.js'

  2. 導出 - export const func = () => {}。

導入模塊使用 import 語法導入依賴項:

// The importing module
import { concat } from './concatModule.js';

concat('a', 'b'); // => 'ab'

導入的模塊本身是用 export 語法導出的模塊:

// The imported module exports components
export const concat = (paramA, paramB) => paramA + paramB;

使用 ES 模塊的方式是靜態的:這意味着模塊之間的依賴關係在編譯時是已知的。

雖然靜態導入在大多數情況下都有效,但有時也會遇到動態加載模塊的情況。

如果 import 用作函數,則可以動態導入模塊— import(pathToModule). 動態導入是 ES2020 開始的 JavaScript 語言功能。

1. 模塊的動態導入

當 import 關鍵字用作函數而不是靜態導入語法時:

const module = await import(path);

它返回一個 Promise 並啓動一個異步任務來加載模塊。如果模塊成功加載,則 Promise 解析爲模塊內容,否則, Promise 拒絕。

path 可以是任何計算結果爲指示路徑的字符串的表達式。有效的路徑表達式是:

// Classic string literals
const module1 = await import('./myModule.js');

// A variable
const path = './myOtherModule.js';
const module2 = await import(path);

// Function call
const getPath = (version) => `./myModule/versions/${version}.js`;
const moduleVersion1 = await import(getPath('v1.0'));
const moduleVersion2 = await import(getPath('v2.0'));

因爲 import(path) 返回一個 Promise ,它非常適合 async/await 語法。例如,讓我們在異步函數中加載一個模塊:

async function loadMyModule() {
  const myModule = await import('./myModule.js');
  // ... use myModule
}

loadMyModule();

2. 導入組件

2.1 命名導出的導入

讓我們考慮以下名爲 namedConcat.js 的模塊:

// namedConcat.js
export const concat = (paramA, paramB) => paramA + paramB;

namedConcat 執行 concat 函數的命名導出。

如果您想動態導入 namedConcat.js 並訪問命名的 export concat,那麼只需通過命名的導出名稱解構解析的模塊對象:

async function loadMyModule() {
  const { concat } = await import('./namedConcat.js');
  concat('b', 'c'); // => 'bc'
}

loadMyModule();
2.2 導入默認導出

如果導入的模塊作爲默認導出,您可以通過 default 從模塊對象讀取屬性來訪問默認導入。

假設 defaultConcat.js 導出功能作爲 default 導出:

// defaultConcat.js
export default (paramA, paramB) => paramA + paramB;

defaultConcat.js 動態導入時,特別是訪問 default 導出時,您只需要讀取 default 屬性即可。

但有一個細微差別。default 是 JavaScript 中的關鍵字,因此它不能用作變量名,因此您只需使用帶別名的解構:

async function loadMyModule() {
  const { default: defaultImport } = await import('./defaultConcat.js');
  defaultImport('b', 'c'); // => 'bc'
}

loadMyModule();
2.3 導入混合內容

如果導入的模塊導出 default 和多個命名導出,那麼您可以使用單個解構輕鬆訪問所有這些組件:

async function loadMyModule() {
  const { 
    default: defaultImport,
    namedExport1,
    namedExport2
  } = await import('./mixedExportModule.js');
  // ...
}

loadMyModule();

3. 何時使用動態導入

我建議在某些條件下導入大模塊時使用動態導入。

async function execBigModule(condition) {
  if (condition) {
    const { funcA } = await import('./bigModuleA.js');
    funcA();
  } else {
    const { funcB } = await import('./bigModuleB.js');
    funcB();
  }
}

execBigModule(true);

對於只有幾十行代碼的小模塊(如 namedConcat.js 或 defaultConcat.js 來自前面的示例),動態導入不值得麻煩。

4. 尾聲

Node.js(版本 13.2 及更高版本)和大多數現代瀏覽器都支持動態導入。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/ei9xPIiObaFkVQV1RLeZiA