- AMD
- CMD
- ES6模塊化
- 各個模塊化規范對比理解
一、AMD
在上一篇js模塊化入門與commonjs解析與應用中詳細的解析了關於commonjs模塊化規范,commonjs采用的用同步加載方式,這導致它並不是瀏覽器理想的模塊化規范。因為瀏覽器需要到服務器加載文件,請求事件遠遠大於本機讀取的時間,如果文件較多,網絡遲緩就會導致頁面癱瘓,所以瀏覽器更希望能夠實現異步加載的方式。
AMD規范則是異步加載模塊,用於指定回調函數。等模塊加載完成以后即可調用回調函數。AMD規范得意的產出就是require.js。
先通過示例來感受以下AMD規范實現的requirejs的應用:
1.1定義工作區間文件結構
1 cmd//工作區間 2 modules-->依賴模塊 3 m1.js-->模塊1 4 m2.js-->模塊2 5 demo.html-->結構文本 6 demo.js-->js主入口文件 7 require.js-->CMD模塊化工具
1.2.1依賴模塊代碼(m1):
1 define(function (){ 2 var name = 'm1-amd'; 3 function getName(){ 4 return name; 5 } 6 return {getName};//{getName}同等與{getName:getName} 7 })
1.2.2依賴模塊代碼(m2):
1 define(['m1'],function(m1){ 2 var msg = 'm2-amd'; 3 function show(){ 4 console.log(msg,m1.getName()); 5 } 6 return {show}; 7 })
1.3JS主入口文件:
1 (function (){ 2 require.config({ 3 paths:{ 4 m2:'./modules/m2', 5 m1:'./modules/m1' 6 } 7 }); 8 require(['m2','jquery'],function(m2,$){ 9 m2.show(); 10 }); 11 })();
1.4在結構文本中引入AMD規范模塊化處理工具require.js,並將主入口文件通過自定義屬性data-main='主入口文件路徑'的方式引入工具中進行處理:
<script src="./require.js" data-main="./demo.js"></script>
AMD的基本規范的全稱“Asynchronous Module Definition”的縮寫,意思是“異步加載模塊”。它采用異步方式加載模塊,模塊的加載不影響后面語句的運行。所有依賴這個模塊的語句,都定義在一個回調函數中,等到加載完成后,這個回調函數才會運行。
AMD規范實際上是requirejs項目在推廣過程中形成的一個產物,先來看看requirejs的基本使用:
requirejs模塊定義:define(id?,dependencies?,factory);==>id:可選參數,用來定義模塊的標識,如果沒有提供該參數,模塊標識就取腳本文件名(去掉擴展名)。==>dependencies:用來傳入當前模塊依賴的模塊名稱數組。==>factory:工廠方法,模塊初始化要執行的函數或對象,如果是函數,它只被執行一次。如果是對象,此對象應該為模塊的輸出值。
requirejs模塊主入口(模塊加載):require.config({paths:{foo:'路徑'}});==>faths:配置所有依賴模塊的路徑。在路徑配置代碼的下方,再通過require(dependencies?,factory)定義主入口文件的依賴關系和回調函數。
在requirejs中還可以實現依賴其他庫和插件,有些插件和庫定義了requirejs的標准接口,比如jQuery,但是有些沒有標准接口,requirejs官方都給出解決方案,可以參考這篇博客:https://www.cnblogs.com/goloving/p/7711104.html。例如我在示例中也測試了jQuery的使用:
1 (function (){ 2 require.config({ 3 paths:{ 4 m2:'./modules/m2', 5 m1:'./modules/m1', 6 jquery:'./jquery-2.0.3' 7 } 8 }); 9 require(['m2','jquery'],function(m2,$){ 10 m2.show(); 11 $('body').css('backgroundColor','#000'); 12 }); 13 })();
關於requirejs更多API可以查看官網的API示例:https://requirejs.org/docs/api.html
二、CMD
在上面一節介紹了AMD規范以及規范實現的requirejs的基本使用,其中提到了AMD相對於Commonjs的優勢在於異步加載模塊,但是我沒由說明這個異步加載在什么時候觸發,到了CMD這里有必要提一下了,AMD規范很重要的一個思想就是依賴前置,意思就是在模塊執行前將所有依賴的模塊先全部加載到本地。而CMD的加載方式也是異步加載,但是觸發加載的時間是在需要某個依賴模塊時再去加載,也有人將CMD說成是同步的,這種同步並不是表現在資源加載上,而是觸發加載的指令與代碼執行是同步的,資源加載還是異步加載模式。
關於Commonjs、AMD、CMD、ES6模塊化的異同在最后會由詳細的對比分析。
2.1.先來看CMD的基本應用:https://www.zhangxinxu.com/sp/seajs/
2.1.1.定義工作區間文件結構
CMD//工作區間 -->modules//依賴模塊 -->m1.js -->m2.js -->m3.js -->m4.js dome.html//結構文本 demo.js//JS主入入口文件 sea.js//模塊化工具
2.1.2.m1模塊代碼
1 define(function(require,exports,module){ 2 var msg = 'm1'; 3 function foo(){ 4 console.log(msg); 5 } 6 module.exports = { 7 foo:foo 8 } 9 })
2.1.3.m2模塊代碼
1 define(function(require,exports,module){ 2 var msg = 'm2'; 3 function bar(){ 4 console.log(msg); 5 } 6 module.exports = bar; 7 })
2.1.4.m3模塊代碼
1 define(function(require,exports,module){ 2 var msg = 'm3'; 3 function foo(){ 4 console.log(msg); 5 } 6 exports.foo = foo; 7 })
2.1.5.m4模塊代碼
1 define(function(require,exports,module){ 2 var msg = 'm4'; 3 // 同步加載 4 var m2 = require('./m2'); 5 m2(); 6 // 異步加載 7 require.async('./m3',function(m3){ 8 m3.foo(); 9 }); 10 function fun(){ 11 console.log(msg); 12 } 13 exports.fun = fun; 14 })
2.1.6.JS主入口文件demo代碼
1 define(function(require,exports,module){ 2 var m1 = require('./modules/m1'); 3 m1.foo(); 4 var m4 = require('./modules/m4'); 5 m4.fun(); 6 })
2.1.7.結構文本demo.html引入模塊化處理工具sea.js,使用seajs工具對象方法user找到主入口文件並解析執行==>seajs.use('主入口文件路徑'):
1 <script src="./sea.js"></script> 2 <script> 3 seajs.use('./demo.js'); 4 </script>
最后代碼打印結果:
這里值得我們關注的是m4打印在m3的前面,這就是CMD依賴就近原則產生的,在執行隊列中異步請求需要等主線程執行完成以后才會調用執行,所以m3作為異步加載模塊,在這個代碼結構中要最后執行。
值得我們注意的seajs也有同步加載模式直接使用require('模塊路徑')獲取模塊,異步模塊加載方式需要使用require.async('模塊路徑',function(模塊名稱){回調執行內容})。
三、ES6模塊化
ES6自帶模塊化,可以使用import關鍵字引入模塊,通過export關鍵字到處模塊,功能較之前幾個方案更為強大,但是由於ES6目前無法在瀏覽器中執行,所以,需要通過babel將不支持的import編譯為當前收到廣泛支持的require。
1 // 引入默認變量及方法和模塊導入的m1 m2變量或方法 2 import theDefault,{m1,m2} from 'lib'; 3 // 引入默認變量及方法 4 import theDefault from 'lib'; 5 // 引入模塊導出的m1 m2變量或方法 6 import {m1,m2} from 'lib'; 7 // 引入模塊導出的m1並且將m1重命名myName m2變量或者方法 8 import * as myLib from 'lib'; 9 // 只將lib加載進來 沒有用來lib中暴露的接口 10 import 'lib'; 11 12 13 // 暴露變量 14 export var a = '123'; 15 // 暴露函數 16 export function myFun(){ 17 18 } 19 // 默認暴露變量函數等 20 export default a = '123'; 21 export function myFun(){}
關於ES6的模塊化會在ES6的相關博客中來詳細解析,這里只做一些基本介紹。
四、各個模塊化規范對比理解
1.什么是模塊化?
答:模塊化是指將一個復雜的系統分解為多個模塊,方便編碼。
2.為什么要用模塊化?
答:降低復雜性,降低代碼耦合度,部署方便,提高效率。
3.模塊化的好處?
答:3.1.避免命名沖突,減少變量空間污染;
3.2.更好的分離代碼,按序加載;
3.3.更高復用性;
3.4.更高可維護性;
4.Webpack支持性:
AMD、ES Modules(推薦使用)、CommonJS因為webpack是基於nodeJS的,所以有必要了解學習。
5.AMD、CMD、CommonJS模塊規范的對比分析:
AMD、CMD可以使用插件引入的方式實現JS代碼模塊化管理,CommonJS不兼容瀏覽器需要Browserify工具在nodejs環境下轉換成瀏覽器可執行的JS文件。
Commonjs采用同步加載,會在一定程度上增加頁面載入時間,如果在這個過程中出現某個模塊錯誤,會導致頁面加載失敗。
AMD、CMD采用異步加載,兩者的區別就是AMD采用前置預加載模式,CMD采用就近原則加載模式。AMD的體驗更好,CMD的性能更優,但是CMD需要考慮異步隊列的執行順序問題,所以這里的更好和更優要相對而言。
(后續深入研究后再來補充)