1 常見的模塊化規(guī)范
- CommonJs (Node.js)
- AMD (RequireJS)
- CMD (SeaJS)
- ES Module(ES6 模塊)
2 模塊化的優(yōu)點(diǎn)
- 在模塊化開發(fā)中词渤,通常一個文件就是一個模塊疟暖。該文件有自己的作用域,只向外暴露特定的變量和函數(shù)撵孤,并且可以按需加載。
- 依賴自動加載呕缭,按需加載埠戳。
- 提高代碼復(fù)用率,方便進(jìn)行代碼的管理贡歧,使得代碼管理更加清晰、規(guī)范赋秀。
- 減少了命名沖突利朵,消除全局變量。
- 目前流行的 js 模塊化規(guī)范有 CommonJS猎莲、AMD绍弟、CMD 以及 ES6 的模塊系統(tǒng)。
3 CommonJS(Node.js)同步加載模塊
CommonJS 是服務(wù)器模塊的規(guī)范著洼,Node.js采用了這個規(guī)范樟遣。
根據(jù) CommonJS
規(guī)范,一個單獨(dú)的文件就是一個模塊身笤,每個模塊都是一個單獨(dú)的作用域豹悬,每個文件中定義的變量(還包括函數(shù)和類),都是私有的液荸,對其他文件是不可見的瞻佛。
CommonJS 規(guī)范加載模塊是同步的,也就是說莹弊,只有加載完成涤久,才能執(zhí)行后面的操作涡尘。
在 CommonJS
中忍弛,加載模塊要使用 require
方法。該方法讀取一個文件并執(zhí)行考抄,最后返回文件內(nèi)部的 exports
對象细疚。
math.js
var x = 5;
var addX = function(value) {
return value + x;
};
module.exports.x = x;
module.exports.addX = addX;
// 也可以改寫為如下
module.exports = {
x: x,
addX: addX,
};
main.js
let math = require('./math.js');
console.log('math.x',math.x);
console.log('math.addX', math.addX(4));
Node.js
主要用于服務(wù)器編程,加載的模塊文件一般都已經(jīng)存在于本地硬盤中川梅,加載起來較快疯兼,不用考慮異步加載的方式然遏,故 CommonJS
的同步加載模塊規(guī)范是比較適用的。
但若在瀏覽器環(huán)境中吧彪,要從服務(wù)器加載模塊待侵,這時就必須采用異步加載模式,故有了 AMD
姨裸,CMD
等解決方案秧倾。
4 AMD(RequireJS)異步加載模塊
-
AMD
=Asynchronous Module Definition
,即 異步模塊定義傀缩。 -
AMD
規(guī)范加載模塊是異步的那先,并允許函數(shù)回調(diào)。不必等到所有模塊都加載完成赡艰,后續(xù)操作也可正常執(zhí)行售淡。 -
AMD
中,使用require
獲取依賴模塊慷垮,使用exports
導(dǎo)出API
揖闸。
// 規(guī)范 API
define(id?, dependencies?, factory);
define.amd = {};
// 定義無依賴的模塊
define({
add: function(x,y){
return x + y;
}
});
// 定義有依賴的模塊
define(["alpha"], function(alpha){
return {
verb: function(){
return alpha.verb() + 1;
}
}
});
異步加載和回調(diào)
require([module], callback) 中 callback
為模塊加載完成后的回調(diào)函數(shù)。
// 加載 math模塊料身,完成之后執(zhí)行回調(diào)函數(shù)
require(['math'], function(math) {
math.add(2, 3);
});
RequireJS
RequireJS 是一個 前端模塊化管理 的工具庫楔壤,遵循
AMD
規(guī)范,RequireJS
是對AMD
規(guī)范的闡述惯驼。
RequireJS
的基本思想為蹲嚣,通過一個函數(shù)將所需或所依賴的模塊全部裝載進(jìn)來,然后返回一個新的函數(shù)(模塊)祟牲。后續(xù)所有關(guān)于新模塊的業(yè)務(wù)代碼隙畜,都在這個函數(shù)內(nèi)部操作。
RequireJS
要求每個模塊均放在獨(dú)立的文件之中说贝,并使用 define
定義模塊议惰,使用 require
方法調(diào)用模塊。
根據(jù)是否有依賴其他模塊的情況乡恕,可分為 獨(dú)立模塊 和 非獨(dú)立模塊言询。
獨(dú)立模塊(不依賴其他模塊,直接定義)
define({
method1: function(){},
method2: function(){}
});
// 等價(jià)于
define(function() {
return {
method1: function(){},
method2: function(){}
}
});
非獨(dú)立模塊(依賴其他模塊)
define([ 'module1', 'module2' ], function(m1, m2) {
...
});
// 等價(jià)于
define(function(require) {
var m1 = require('module1');
var m2 = require('module2');
...
});
調(diào)用模塊(使用 require
方法)
require(['foo', 'bar'], function(foo, bar) {
foo.func();
bar.func();
});
5 CMD(SeaJS)異步模塊
CMD 的定義
-
CMD
=Common Module Definition
傲宜,即 通用模塊定義运杭。CMD
是SeaJS
在推廣過程中對模塊定義的規(guī)范化產(chǎn)出。 -
CMD
規(guī)范和AMD
規(guī)范類似函卒,都主要運(yùn)行于瀏覽器端辆憔,寫法上看起來也很類似。主要區(qū)別,在于 模塊初始化時機(jī)虱咧。
AMD 與 CMD 的異同
-
AMD
中熊榛,只要模塊作為依賴時就會加載并進(jìn)行初始化。 -
CMD
中腕巡,模塊作為依賴且被引用時才會初始化玄坦,否則只會加載。 -
CMD
推崇依賴就近绘沉,可以把依賴寫進(jìn)你的代碼中的任意一行营搅。AMD
推崇依賴前置。 -
AMD
的API
默認(rèn)是一個當(dāng)多個用梆砸,CMD
嚴(yán)格的區(qū)分推崇職責(zé)單一转质。例如:AMD
里require
分全局的和局部的。CMD里面沒有全局的require
帖世,提供seajs.use()
來實(shí)現(xiàn)模塊系統(tǒng)的加載啟動休蟹。CMD
里每個API
都簡單純粹。
// AMD
define(['./a','./b'], function (a, b) {
// 依賴一開始就寫好
a.test();
b.test();
});
// CMD
define(function (require, exports, module) {
// 依賴可以就近書寫
var a = require('./a');
a.test();
...
// 軟依賴
if (status) {
var b = require('./b');
b.test();
}
});
Sea.js
使用 Sea.js日矫,在書寫文件時需要遵守 CMD(Common Module Definition)模塊定義規(guī)范赂弓,一個文件就是一個模塊。
用法
- 通過
exports
暴露接口哪轿。這意味著不需要命名空間了盈魁,更不需要全局變量。這是一種徹底的命名沖突解決方案窃诉。 - 通過
require
引入依賴杨耙。這可以讓依賴內(nèi)置,開發(fā)者只需關(guān)心當(dāng)前模塊的依賴飘痛,其他事情Sea.js
都會自動處理好珊膜。對模塊開發(fā)者來說,這是一種很好的 關(guān)注度分離宣脉,能讓程序員更多地享受編碼的樂趣车柠。 - 通過
define
定義模塊。
示例
例如塑猖,對于下述 util.js
代碼
var org = {};
org.CoolSite = {};
org.CoolSite.Utils = {};
org.CoolSite.Utils.each = function (arr) {
// 實(shí)現(xiàn)代碼
};
org.CoolSite.Utils.log = function (str) {
// 實(shí)現(xiàn)代碼
};
可以采用 SeaJS 重寫為
define(function(require, exports) {
exports.each = function (arr) {
// 實(shí)現(xiàn)代碼
};
exports.log = function (str) {
// 實(shí)現(xiàn)代碼
};
});
通過 exports
就可以向外提供接口竹祷。通過 require('./util.js')
就可以拿到 util.js
中通過 exports
暴露的接口。這里的 require
可以認(rèn)為是 Sea.js
給 JavaScript 語言增加的一個語法關(guān)鍵字羊苟,通過 require
可以獲取其他模塊提供的接口塑陵。
define(function(require, exports) {
var util = require('./util.js');
exports.init = function() {
// 實(shí)現(xiàn)代碼
};
});
SeaJS 與 RequireJS 區(qū)別
二者區(qū)別主要表現(xiàn)在 模塊初始化時機(jī)
AMD(RequireJS)中只要模塊作為依賴時,就會加載并初始化践险。即盡早地執(zhí)行(依賴)模塊猿妈。相當(dāng)于所有的 require 都被提前了,而且模塊的執(zhí)行的順序也不一定就是 require 的書寫順序巍虫。
CMD(SeaJS)中彭则,模塊作為依賴且被引用時才會初始化,否則只會加載占遥。即只會在模塊真正需要使用的時候才初始化俯抖。模塊加載的順序是嚴(yán)格按照 require 書寫的順序來的。
規(guī)范 | 生態(tài) | 書寫 | 易于實(shí)現(xiàn) | NodeJS 模塊相似性 |
---|---|---|---|---|
AMD | ★★★★★ | ★★★ | ★★★★★ | ★★★ |
CMD | ★★ | ★★★★★ | ★★★ | ★★★★★ |
從規(guī)范上來說瓦胎,AMD 更加簡單且嚴(yán)謹(jǐn)芬萍,適用性更廣,而在 RequireJS 強(qiáng)力的推動下搔啊,在國外幾乎成了事實(shí)上的異步模塊標(biāo)準(zhǔn)柬祠,各大類庫也相繼支持 AMD 規(guī)范。
但從 SeaJS 與 CMD 來說负芋,也做了很多不錯東西:1. 相對自然的依賴聲明風(fēng)格 2. 小而美的內(nèi)部實(shí)現(xiàn) 3. 貼心的外圍功能設(shè)計(jì) 4. 更好的中文社區(qū)支持漫蛔。
6 UMD
-
UMD
=Universal Module Definition
,即 通用模塊定義旧蛾,它是AMD
和CommonJS
的糅合莽龟。 -
AMD
模塊以 瀏覽器第一的原則 發(fā)展,選擇異步加載锨天。CommonJS
模塊以 服務(wù)器第一原則 發(fā)展毯盈,選擇同步加載。由此病袄,迫使人們又想出另一個更通用的模式UMD
(Universal Module Definition)搂赋,實(shí)現(xiàn)跨平臺的解決方案。 -
UMD
先判斷支持Node.js
的模塊(exports
)是否存在益缠,存在則使用Node.js
模塊模式厂镇。再判斷支持AMD
(define
)是否存在,存在則使用AMD
方式加載模塊左刽。
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global = global || self, global.utilName = factory());
}(this, function () {
//module ...
});
7 ES Module(ES6 模塊)
CommonJS 和 ES6 模塊 的區(qū)別
-
CommonJS
模塊是 運(yùn)行時加載捺信,ES6 模塊是 編譯時輸出接口。 - ES6 模塊 輸出的是值的引用欠痴,輸出接口動態(tài)綁定迄靠,而
CommonJS
輸出的是值的拷貝。
CommonJS 輸出值的拷貝
CommonJS 模塊輸出的是值的拷貝喇辽,導(dǎo)出值改變不會導(dǎo)致導(dǎo)入值改變掌挚。
lib.js
var counter = 3;
var obj = {
name: 'David'
};
function changeValue() {
counter++;
obj.name = 'Peter';
};
module.exports = {
counter: counter,
obj: obj,
changeValue: changeValue,
};
main.js
var mod = require('./lib');
console.log(mod.counter); // 3
console.log(mod.obj.name); // 'David'
mod.changeValue();
console.log(mod.counter); // 3
console.log(mod.obj.name); // 'Peter'
// But
console.log(require('./lib').counter); // 3
console.log(require('./lib').obj.name); // 'Peter'
-
counter
是基本類型值,模塊內(nèi)部值的變化 不影響 輸出的值變化菩咨。 -
obj
是引用類型值吠式,模塊內(nèi)部值的變化 會影響 輸出的值變化陡厘。 - 上述兩點(diǎn)區(qū)別,可類比基本類型和引用類型的賦值操作特占。
也可以借助取值函數(shù)(getter
)糙置,將 counter
轉(zhuǎn)為引用類型值,效果如下是目。
在類的內(nèi)部谤饭,可以使用
get
和set
關(guān)鍵字,對某個屬性設(shè)置存值函數(shù)和取值函數(shù)懊纳,攔截該屬性的存取行為揉抵。 —— class | 阮一峰
lib.js
var counter = 3;
function incCounter() {
counter++;
}
module.exports = {
get counter() {
return counter
},
incCounter: incCounter,
};
main.js
var mod = require('./lib');
console.log(mod.counter); // 3
mod.incCounter();
console.log(mod.counter); // 4
ES6 輸出值的引用
ES6 模塊是動態(tài)關(guān)聯(lián)模塊中的值,輸出的是值的引用嗤疯。原始值變了冤今,import
加載的值也會跟著變。
ES6
模塊的運(yùn)行機(jī)制與CommonJS
不一樣茂缚。JS 引擎對腳本靜態(tài)分析時辟汰,遇到模塊加載命令import
,就會生成一個只讀引用阱佛。等到腳本真正執(zhí)行時帖汞,再根據(jù)這個只讀引用,到被加載的那個模塊里面去取值凑术。ES6 模塊中翩蘸,原始值變了,import
加載的值也會跟著變淮逊。因此催首,ES6 模塊是動態(tài)引用,并且不會緩存值泄鹏。 —— ES6 Module 的加載實(shí)現(xiàn) | 阮一峰
// lib.js
export let counter = 3;
export function incCounter() {
counter++;
}
// main.js
import { counter, incCounter } from './lib';
console.log(counter); // 3
incCounter();
console.log(counter); // 4
CommonJS 運(yùn)行時加載 ES6靜態(tài)編譯
CommonJS
模塊是運(yùn)行時加載郎任,ES6 模塊是編譯時輸出接口。
這是因?yàn)椋?strong>CommonJS
加載的是一個對象(即 module.exports
屬性)备籽,該對象只有在腳本運(yùn)行完才會生成舶治。而 ES6
模塊不是對象,它的對外接口只是一種靜態(tài)定義车猬,在代碼靜態(tài)解析階段就會生成霉猛。
ES6 模塊是編譯時輸出接口,因此有如下2個特點(diǎn)
-
import
命令會被 JS 引擎靜態(tài)分析珠闰,優(yōu)先于模塊內(nèi)的其他內(nèi)容執(zhí)行 -
export
命令會有變量聲明提升的效果
import 優(yōu)先執(zhí)行
在文件中的任何位置引入 import
模塊都會被提前到文件頂部
// a.js
console.log('a.js')
import { foo } from './b';
// b.js
export let foo = 1;
console.log('b.js 先執(zhí)行');
// 執(zhí)行結(jié)果:
// b.js 先執(zhí)行
// a.js
雖然 a
模塊中 import
引入晚于 console.log('a')
惜浅,但是它被 JS 引擎通過靜態(tài)分析,提到模塊執(zhí)行的最前面伏嗜,優(yōu)于模塊中的其他部分的執(zhí)行坛悉。
export 命令變量提升效果
由于 import
和 export
是靜態(tài)執(zhí)行伐厌,所以 import
和 export
具有變量提升效果。即 import
和 export
命令在模塊中的位置并不影響程序的輸出裸影。
// a.js
import { foo } from './b';
console.log('a.js');
export const bar = 1;
export const bar2 = () => {
console.log('bar2');
}
export function bar3() {
console.log('bar3');
}
// b.js
export let foo = 1;
import * as a from './a';
console.log(a);
// 執(zhí)行結(jié)果:
// { bar: undefined, bar2: undefined, bar3: [Function: bar3] }
// a.js
a
模塊引用了 b
模塊挣轨,b
模塊也引用了 a
模塊,export
聲明的變量也是優(yōu)于模塊其它內(nèi)容的執(zhí)行的空民。但具體對變量賦值需要等到執(zhí)行到相應(yīng)代碼的時候刃唐。
ES6 模塊和 CommonJS 相同點(diǎn)
模塊不會重復(fù)執(zhí)行
重復(fù)引入某個相同的模塊時羞迷,模塊只會執(zhí)行一次界轩。
循環(huán)依賴
CommonJS 模塊循環(huán)依賴
CommonJS 模塊的重要特性是加載時執(zhí)行,即腳本代碼在 require
的時候衔瓮,就會全部執(zhí)行浊猾。一旦出現(xiàn)某個模塊被“循環(huán)加載”,就只輸出已經(jīng)執(zhí)行的部分热鞍,還未執(zhí)行的部分不會輸出葫慎。
Demo 1
//a.js
exports.done = false;
var b = require('./b.js');
console.log('在 a.js 之中,b.done =', b.done);
exports.done = true;
console.log('a.js 執(zhí)行完畢');
上面代碼之中薇宠,a.js
腳本先輸出一個 done
變量偷办,然后加載另一個腳本文件 b.js
。注意澄港,此時 a.js
代碼就停在這里椒涯,等待 b.js
執(zhí)行完畢,再往下執(zhí)行回梧。
再看 b.js
的代碼废岂。
//b.js
exports.done = false;
var a = require('./a.js');
console.log('在 b.js 之中,a.done =', a.done);
exports.done = true;
console.log('b.js 執(zhí)行完畢');
上面代碼之中狱意,b.js
執(zhí)行到第二行湖苞,就會去加載 a.js
,這時详囤,就發(fā)生了“循環(huán)加載”财骨。系統(tǒng)會在 a.js
模塊對應(yīng)對象的 exports
屬性取值〔亟悖可是因?yàn)?a.js
還沒有執(zhí)行完蚓再,從 exports
屬性只能取回已經(jīng)執(zhí)行的部分,而不是最后的值包各。
a.js
已經(jīng)執(zhí)行的部分摘仅,只有一行。
exports.done = false;
因此问畅,對于 b.js
來說娃属,它從 a.js
只輸入一個變量 done
六荒,值為 false
。
然后矾端,b.js
接著往下執(zhí)行掏击,等到全部執(zhí)行完畢,再把執(zhí)行權(quán)交還給 a.js
秩铆。于是砚亭,a.js
接著往下執(zhí)行,直到執(zhí)行完畢殴玛。我們寫一個腳本 main.js
捅膘,驗(yàn)證這個過程。
var a = require('./a.js');
var b = require('./b.js');
console.log('在 main.js 之中, a.done=, b.done=', a.done, b.done);
執(zhí)行 main.js
滚粟,運(yùn)行結(jié)果如下寻仗。
$ node main.js
在 b.js 之中,a.done = false
b.js 執(zhí)行完畢
在 a.js 之中凡壤,b.done = true
a.js 執(zhí)行完畢
在 main.js 之中, a.done = true, b.done = true
上面的代碼證明了2點(diǎn)
- 在
b.js
之中署尤,a.js
沒有執(zhí)行完畢,只執(zhí)行了第一行亚侠。 -
main.js
執(zhí)行到第二行時曹体,不會再次執(zhí)行b.js
,而是輸出緩存的b.js
的執(zhí)行結(jié)果硝烂,即它的第四行箕别。
exports.done = true;
總之,CommonJS 輸入的是被輸出值的拷貝钢坦,不是引用究孕。
另外,由于 CommonJS 模塊遇到循環(huán)加載時爹凹,返回的是當(dāng)前已經(jīng)執(zhí)行的部分的值厨诸,而不是代碼全部執(zhí)行后的值,兩者可能會有差異禾酱。所以微酬,輸入變量的時候,必須非常小心颤陶。
var a = require('a'); // 安全的寫法 導(dǎo)入整體颗管,保證 module 已經(jīng)執(zhí)行完成
var foo = require('a').foo; // 危險(xiǎn)的寫法
exports.good = function (arg) {
return a.foo('good', arg); // 使用的是 a.foo 的最新值
};
exports.bad = function (arg) {
return foo('bad', arg); // 使用的是一個部分加載時的值
};
上面代碼中,如果發(fā)生循環(huán)加載滓走,require('a').foo
的值很可能后面會被改寫垦江,改用 require('a')
會更保險(xiǎn)一點(diǎn)。
Demo 2
// a.js
console.log('a starting');
exports.done = false;
const b = require('./b');
console.log('in a, b.done =', b.done);
exports.done = true;
console.log('a done');
// b.js
console.log('b starting');
exports.done = false;
const a = require('./a');
console.log('in b, a.done =', a.done);
exports.done = true;
console.log('b done');
// node a.js
// 執(zhí)行結(jié)果:
// a starting
// b starting
// in b, a.done = false
// b done
// in a, b.done = true
// a done
從上面的執(zhí)行過程中搅方,可以看到比吭,在 CommonJS 規(guī)范中绽族,當(dāng)遇到 require()
語句時,會執(zhí)行 require
模塊中的代碼衩藤,并緩存執(zhí)行的結(jié)果吧慢,當(dāng)下次再次加載時不會重復(fù)執(zhí)行,而是直接取緩存的結(jié)果赏表。正因?yàn)榇思焓霈F(xiàn)循環(huán)依賴時才不會出現(xiàn)無限循環(huán)調(diào)用的情況。
ES6 模塊循環(huán)依賴
跟 CommonJS 模塊一樣瓢剿,ES6 不會再去執(zhí)行重復(fù)加載的模塊逢慌,又由于 ES6 動態(tài)輸出綁定的特性,能保證 ES6 在任何時候都能獲取其它模塊當(dāng)前的最新值跋选。
ES6 動態(tài) import()
ES6 模塊在編譯時就會靜態(tài)分析涕癣,優(yōu)先于模塊內(nèi)的其他內(nèi)容執(zhí)行哗蜈,所以導(dǎo)致了我們無法寫出像下面這樣的代碼
if(some condition) {
import a from './a';
}else {
import b from './b';
}
// or
import a from (str + 'b');
因?yàn)榫幾g時靜態(tài)分析前标,導(dǎo)致了我們在引用的時候,無法使用 條件語句 或者 拼接字符串模塊距潘,因?yàn)檫@些都是需要在運(yùn)行時才能確定的結(jié)果在 ES6 模塊是不被允許的炼列,所以 動態(tài)引入import()
應(yīng)運(yùn)而生。
import()
允許你在運(yùn)行時動態(tài)地引入 ES6 模塊音比,想到這俭尖,你可能也想起了 require.ensure
這個語法,但是它們的用途卻截然不同的洞翩。
require.ensure
的出現(xiàn)是 webpack
的產(chǎn)物稽犁,它是因?yàn)闉g覽器需要一種異步的機(jī)制可以用來異步加載模塊,從而減少初始的加載文件的體積骚亿,所以如果在服務(wù)端的話已亥, require.ensure
就無用武之地了,因?yàn)榉?wù)端不存在異步加載模塊的情況来屠,模塊同步進(jìn)行加載就可以滿足使用場景了虑椎。 CommonJS 模塊可以在運(yùn)行時確認(rèn)模塊加載。
而 import()
則不同俱笛,它主要是為了解決 ES6 模塊無法在運(yùn)行時確定模塊的引用關(guān)系捆姜,所以需要引入 import()
。
先來看下它的用法
- 動態(tài)的
import()
提供一個基于Promise
的API
- 動態(tài)的
import()
可以在腳本的任何地方使用import()
接受字符串文字迎膜,可以根據(jù)需要構(gòu)造說明符
// a.js
const str = './b';
const flag = true;
if(flag) {
import('./b').then(({foo}) => {
console.log(foo);
})
}
import(str).then(({foo}) => {
console.log(foo);
})
// b.js
export const foo = 'foo';
// babel-node a.js
// 執(zhí)行結(jié)果
// foo
// foo
當(dāng)然泥技,如果在瀏覽器端的 import()
的用途就會變得更廣泛,比如 按需異步加載模塊磕仅,那么就和 require.ensure
功能類似了珊豹。
因?yàn)槭腔?Promise
的镊讼,所以如果你想要同時加載多個模塊的話,可以是 Promise.all
進(jìn)行并行異步加載平夜。
Promise.all([
import('./a.js'),
import('./b.js'),
import('./c.js'),
]).then(([a, {default: b}, {c}]) => {
console.log('a.js is loaded dynamically');
console.log('b.js is loaded dynamically');
console.log('c.js is loaded dynamically');
});
還有 Promise.race
方法蝶棋,它檢查哪個 Promise
被首先 resolved
或 reject
。我們可以使用 import()
來檢查哪個 CDN
速度更快:
const CDNs = [
{
name: 'jQuery.com',
url: 'https://code.jquery.com/jquery-3.1.1.min.js'
},
{
name: 'googleapis.com',
url: 'https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js'
}
];
console.log(`------`);
console.log(`jQuery is: ${window.jQuery}`);
Promise.race([
import(CDNs[0].url).then(()=>console.log(CDNs[0].name, 'loaded')),
import(CDNs[1].url).then(()=>console.log(CDNs[1].name, 'loaded'))
]).then(()=> {
console.log(`jQuery version: ${window.jQuery.fn.jquery}`);
});
當(dāng)然忽妒,如果你覺得這樣寫還不夠優(yōu)雅玩裙,也可以結(jié)合 async/await
語法糖來使用。
async function main() {
const myModule = await import('./myModule.js');
const {export1, export2} = await import('./myModule.js');
const [module1, module2, module3] =
await Promise.all([
import('./module1.js'),
import('./module2.js'),
import('./module3.js'),
]);
}
動態(tài) import()
為我們提供了以異步方式使用 ES 模塊的額外功能段直。
根據(jù)我們的需求動態(tài)或有條件地加載它們吃溅,這使我們能夠更快,更好地創(chuàng)建更多優(yōu)勢應(yīng)用程序鸯檬。
8 webpack中加載3種模塊 | 語法
Webpack 允許使用不同的模塊類型决侈,但是底層
必須使用同一種實(shí)現(xiàn)。所有的模塊可以直接在盒外運(yùn)行喧务。
- ES6 模塊
import MyModule from './MyModule.js';
- CommonJS(require)
var MyModule = require('./MyModule.js');
- AMD
define(['./MyModule.js'], function (MyModule) {});