如何動(dòng)態(tài)導(dǎo)入ECMAScript模塊?
ECMAScript(又名ES2015或ES)模塊是在JavaScript中組織內(nèi)聚代碼塊的一種方法。
ES模塊系統(tǒng)有2個(gè)部分:
- import模塊 - 使用 import { func } from './myModule'
- export模塊- 使用 export const func = () => {}
import 模塊是使用 import 語(yǔ)法導(dǎo)入依賴項(xiàng)的模塊:
- import { concat } from './concatModule';
- concat('a', 'b'); // => 'ab'
而被導(dǎo)入的模塊使用export語(yǔ)法從自身導(dǎo)出組件:
- export const concat = (paramA, paramB) => paramA + paramB;
import { concat } from './concatModule'使用ES模塊的方式是靜態(tài)的:意味著模塊之間的依賴關(guān)系在編譯時(shí)就已經(jīng)知道了。
雖然靜態(tài)導(dǎo)入在大多數(shù)情況下是有效的,但有時(shí)我們想節(jié)省客戶的帶寬并有條件地加載模塊。
為了實(shí)現(xiàn)這一點(diǎn),我們可以用不同的方式使用 import(pathToModule) 語(yǔ)法對(duì)模塊進(jìn)行新的動(dòng)態(tài)導(dǎo)入:作為一個(gè)函數(shù)。動(dòng)態(tài)導(dǎo)入是ES2020開(kāi)始的一個(gè)JavaScript語(yǔ)言特性。
1. 動(dòng)態(tài)模塊的導(dǎo)入
當(dāng)import關(guān)鍵字用作函數(shù)而不是靜態(tài)導(dǎo)入語(yǔ)法時(shí):
- const module = await import(pathToModule);
它返回一個(gè)promise ,并開(kāi)始一個(gè)加載模塊的異步任務(wù)。如果模塊被成功加載,那么promise就會(huì)解析到模塊的內(nèi)容,否則,promise 就會(huì)被拒絕。
請(qǐng)注意,pathToModule可以是任何表達(dá)式,其值為表示導(dǎo)入模塊路徑的字符串。有效的值是普通的字符串字面意義(如./myModule)或有字符串的變量。
例如,我們?cè)谝粋€(gè)異步函數(shù)中加載一個(gè)模塊。
- async function loadMyModule() {
- const myModule = await import('./myModule');
- // ... use myModule
- }
- loadMyModule();
有趣的是,與靜態(tài)導(dǎo)入相反,動(dòng)態(tài)導(dǎo)入接受以模塊路徑求值的表達(dá)式。
- async function loadMyModule(pathToModule) {
- const myModule = await import(pathToModule);
- // ... use myModule
- }
- loadMyModule('./myModule');
現(xiàn)在,了解了如何加載模塊后,我們來(lái)看看如何從導(dǎo)入的模塊中提取組件。
2.導(dǎo)入組件
2.1 導(dǎo)入命名組件
考慮下面的模塊:
- // namedConcat.js
- export const concat = (paramA, paramB) => paramA + paramB;
這里導(dǎo)出了一個(gè) concat 函數(shù)。
如果想動(dòng)態(tài)導(dǎo)入namedConcat.js,并訪問(wèn)命名的導(dǎo)出concat,那么只需通解構(gòu)的方式就行了:
- async function loadMyModule() {
- const { concat } = await import('./namedConcat');
- concat('b', 'c'); // => 'bc'
- }
- loadMyModule();
2.2 默認(rèn)導(dǎo)出
如果模塊是默認(rèn)導(dǎo)出的,我們可以使用default屬性來(lái)訪問(wèn)。
還是上面的例子,我們將defaultConcat.js里面的concat函數(shù)默認(rèn)導(dǎo)出:
- // defaultConcat.js
- export default (paramA, paramB) => paramA + paramB;
在動(dòng)態(tài)導(dǎo)入模塊中,可以使用default屬性來(lái)訪問(wèn):
- async function loadMyModule() {
- const { default: defaultImport } = await import('./defaultConcat');
- defaultImport('b', 'c'); // => 'bc'
- }
- loadMyModule();
注意,default在JavaScript中是一個(gè)關(guān)鍵字,所以它不能用作變量名。
2.3導(dǎo)入混合形式
如果模塊里面既有默認(rèn)導(dǎo)出也有命名導(dǎo)出,同樣也是使用解構(gòu)的方式來(lái)訪問(wèn):
- async function loadMyModule() {
- const {
- default: defaultImport,
- namedExport1,
- namedExport2
- } = await import('./mixedExportModule');
- // ...
- }
- loadMyModule();
3.何時(shí)使用動(dòng)態(tài)導(dǎo)入
建議在模塊比較大的,或者要根據(jù)條件才導(dǎo)入的模塊可以使用動(dòng)態(tài)導(dǎo)入。
- async function execBigModule(condition) {
- if (condition) {
- const { funcA } = await import('./bigModuleA');
- funcA();
- } else {
- const { funcB } = await import('./bigModuleB');
- funcB();
- }
- }
- execBigModule(true);
對(duì)于小模塊(如前面例子中的namedConcat.js或defaultConcat.js),只有幾十行代碼,使用動(dòng)態(tài)導(dǎo)入在點(diǎn)殺雞用牛刀感覺(jué)。
總結(jié)
當(dāng)調(diào)用 import(pathToModule) 作為一個(gè)函數(shù)時(shí),其參數(shù)表示一個(gè)模塊的指定符(又稱路徑),那么就會(huì)動(dòng)態(tài)加載該模塊。
在這種情況下,module = await import(pathToModule) 返回一個(gè) promise ,該承諾解析為一個(gè)包含導(dǎo)入模塊組件的對(duì)象。
Node.js(13.2及以上版本)和大多數(shù)現(xiàn)代瀏覽器都支持動(dòng)態(tài)導(dǎo)入。
作者:Dmitri Pavlutin
譯者:前端小智 來(lái)源:dmitripavlutin原文:https://dmitripavlutin.com/ecmascript-modules-dynamic-import/
本文轉(zhuǎn)載自微信公眾號(hào)「大遷世界」,可以通過(guò)以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系大遷世界公眾號(hào)。