前端模塊加載規范

模塊加載規范:CommonJS、AMD 和 CMD,而框架Node.js、RequireJS 和 Seajs 分別實現了上述規范。

沒有這些模塊加載規范時,加載模塊是一種什么情況?
只能在HTML中通過<script>來引入js文件,同時無法區分函數來源于哪個js文件,而且要用過多全局變量。

使用模塊加載后,這些問題都解決了。

CommonJS:

Node.js使用的規范,同步加載JS腳本。在服務端沒問題,因為文件都在磁盤上。但因為瀏覽器的特性,需要異步加載js,否則會失去響應。所以該規范無法在瀏覽器直接使用。

瀏覽器不兼容CommonJS的根本原因,在于缺少四個Node.js環境的變量:module、exports、require、global

參考:瀏覽器加載 CommonJS 模塊的原理與實現

AMD:

Angular.js、require.js使用的規范,異步加載JS。前置加載,就是在寫主邏輯之前必須指定所有的依賴,并且等待所有的依賴被異步加載完后執行回調函數。依賴的模塊同時被加載,沒有順序依賴。

AMD優點:AMD是前置依賴,依賴項最好是已知必須要依賴的,這樣可以一次性將必須用到的JS腳本全部加載,后續可以直接使用,不需要再遍歷整個函數體查找依賴,提高性能。

AMD缺點:開發者必須顯式指明依賴,這會使開發成本變大,比如當代碼達到幾百上千行的時候,忽然發現需要增加一個依賴,不得不回到函數頂端將依賴添加到數組中。

require(['module1', 'module2'], function(m1, m2){

//主回調邏輯

m1.test();

m2.test();

})

CMD:

Sea.js使用的規范。就近加載。Sea.js遇到依賴后,只會去下載JS文件,等待所有的依賴下載完成后,再從頭開始執行主邏輯。因此被依賴模塊的執行順序和書寫順序完全一致。

優點:開發便利,動態加載,可以把依賴寫進代碼任意一行。

缺點:如下示例代碼,代碼在運行時是不知道依賴的,需要遍歷所有的require關鍵字,找到后面的依賴,具體做法就是將function toString后,用正則匹配出關鍵字后面的依賴。這是一種犧牲性能來換取開發便利的方法。

define(function(require, exports, module){

var foo= require('foo');//同步加載

foo.add(1, 2);

require.async('math', fucntion(math){//異步加載

math.add(1,2);

})

});

上面對AMD和CMD說的都是必須依賴(可稱為強依賴)的情況,還有一些依賴,是在特定條件成立后才需要加載的(可稱為弱依賴)。

if(status){a.doSomething()}

這種情況可以用異步回調方式實現:

AMD實現:if(status){

async(['a'], function(a){

a.doSomething();

})

}


CMD實現:if(status){

require.async('a', function(a){

?a.doSomething();

})

}

總結:

對于必須依賴(稱為強依賴),如果性能優先,可采用AMD前置依賴模式。

如果開發成本優先,可采用CMD就近依賴模式。

對于弱依賴,只需要將弱依賴的部分改寫到回調函數內即可。

ES6模塊化:

在 ES6 中,我們使用 export 關鍵字來導出模塊,使用 import 關鍵字引用模塊。如果js解析器不識別ES6語法,需要將ES6語法轉換成低版本語法。目前所有的引擎都還沒有實現import,我們在node中使用babel支持ES6,也僅僅是將ES6轉碼為ES5再執行,import語法會被轉碼為require。

參考:

ES6模塊的import和export用法總結

Node中沒搞明白require和import,你會被坑的很慘

寫到這里,想起當前做的項目,有很多插件、配置JS腳本,是在HTML通過'<script>'腳本同步引入的,這種寫法很懶省事,但會降低性能。看了'<script>'的用法,是可以異步引入的:

1.同步加載<script src="./a.js"></script>

同步模式,又稱阻塞模式,會阻止瀏覽器的后續處理,停止了后續的解析,因此停止了后續的文件加載(如圖像)、渲染、代碼執行。

js 之所以要同步執行,是因為 js 中可能有輸出 document 內容、修改dom、重定向等行為,所以默認同步執行才是安全的。

2.帶defer屬性defer屬性聲明這個腳本中將不會有 document.write 或 dom 修改。瀏覽器將會并行下載 a.js 和其它有 defer 屬性的script,而不會阻塞頁面后續處理。注:所有的defer 腳本保證是按順序依次執行的。

3.帶async屬性<script src="./a.js" async></script>

async屬性是HTML5新增的。作用和defer類似,但是它將在下載后盡快執行,不能保證腳本會按順序執行。它們將在onload 事件之前完成。

defer屬性在IE 4.0中就實現了,超過13年了!Firefox 從 3.5 開始支持defer屬性 。

Firefox 3.6、Opera 10.5、IE 9 和 最新的Chrome 和 Safari 都支持 async 屬性。可以同時使用 async 和 defer,這樣IE 4之后的所有 IE 都支持異步加載。


感謝:

詳解JavaScript模塊化開發

Node中沒搞明白require和import,你會被坑的很慘

ES6模塊的import和export用法總結

瀏覽器加載 CommonJS 模塊的原理與實現

JavaScript異步加載詳解

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容