之前公司開發(fā)的某個(gè)大數(shù)據(jù)產(chǎn)品吨凑,所有的功能都集中在了一個(gè)頁(yè)面里面片林,久而久之就造成了頁(yè)面加載卡頓大大影響了體驗(yàn)效果;后來(lái)引用了RequireJS來(lái)進(jìn)行模塊化的開發(fā)來(lái)解決這個(gè)問題怀骤;不管從前后端未分離的RequireJS還是使用Node開發(fā)的CommonJS,模塊化開發(fā)無(wú)處不在,模塊化的開發(fā)方式可以提高代碼復(fù)用率焕妙,方便進(jìn)行代碼的管理蒋伦。通常一個(gè)文件就是一個(gè)模塊,有自己的作用域籽慢,只向外暴露它的接口硼瓣。目前流行的js模塊化規(guī)范有CommonJS、AMD牲证、CMD以及ES6的模塊系統(tǒng)研叫。那么在眾多模塊化開發(fā)方案當(dāng)中我們應(yīng)該使用哪種方案锤窑?
原始方法
<script>標(biāo)簽
這是最原始的 JavaScript 文件加載方式,如果把每一個(gè)文件看做是一個(gè)模塊嚷炉,那么他們的接口通常是暴露在全局作用域下渊啰,也就是定義在window對(duì)象中,不同模塊的接口調(diào)用都是一個(gè)作用域中申屹,一些復(fù)雜的框架绘证,會(huì)使用命名空間的概念來(lái)組織這些模塊的接口。
這種原始的加載方式暴露了一些顯而易見的弊端:
全局作用域下容易造成變量沖突
文件只能按照<script>的書寫順序進(jìn)行加載
開發(fā)人員必須主觀解決模塊和代碼庫(kù)的依賴關(guān)系
在大型項(xiàng)目中各種資源難以管理哗讥,長(zhǎng)期積累的問題導(dǎo)致代碼庫(kù)混亂不堪
一嚷那、CommonJS
我們?cè)谑褂肗ode開發(fā)程序的時(shí)候,這個(gè)程序由很多個(gè)模塊組成杆煞,每一個(gè)模塊都是一個(gè)文件(一個(gè)單獨(dú)的作用域)魏宽。Node模塊采用的就是CommonJS規(guī)范,該規(guī)范的核心思想是允許模塊通過?require?方法來(lái)同步加載所要依賴的其他模塊决乎,然后通過? module.exports?來(lái)導(dǎo)出需要暴露的接口队询。
CommonJS是服務(wù)端的JS規(guī)范,上面提到了每個(gè)文件都是一個(gè)作用域瑞驱,在該模塊內(nèi)部定義的變量其他模塊沒有辦法讀取的到娘摔,除非定義為global對(duì)象的屬性,
輸出模塊: 每個(gè)模塊只有一個(gè)出口唤反, module.export對(duì)象凳寺,我們把想要輸出的模塊放入里面;
加載模塊: 加載一個(gè)模塊的時(shí)候我們采用require方法彤侍,這個(gè)方法會(huì)讀取一個(gè)文件并返回文件內(nèi)部的module.export對(duì)象肠缨;
CommonJS模塊的特點(diǎn)如下。
1盏阶、所有代碼都運(yùn)行在模塊作用域晒奕,不會(huì)污染全局作用域。
2名斟、模塊可以多次加載脑慧,但是只會(huì)在第一次加載時(shí)運(yùn)行一次,然后運(yùn)行結(jié)果就被緩存了砰盐,以后再加載闷袒,就直接讀取緩存結(jié)果。要想讓模塊再次運(yùn)行岩梳,必須清除緩存囊骤。
3晃择、NMP中已經(jīng)有將近20萬(wàn)個(gè)可以使用模塊包
缺點(diǎn):
1、同步的模塊加載方式不適合在瀏覽器環(huán)境中也物,同步意味著阻塞加載宫屠,
2、瀏覽器資源是異步加載的不能非阻塞的并行加載多個(gè)模塊
?CommonJs所加載的模塊一般都已經(jīng)存在本地的硬盤里面滑蚯,當(dāng)我們執(zhí)行某個(gè)文件的時(shí)候會(huì)一同加載文件里面require所引入的文件浪蹂,加載起來(lái)非常快膘魄,不要考慮異步加載的方式乌逐。 但是這個(gè)只是在于服務(wù)器端,如果是瀏覽器端创葡,要從服務(wù)器加載模塊就必須采用異步的方式浙踢,于是乎就有了AMD CMD的解決方案;
二灿渴、AMD
Asynchronous Module Definition(?異步模塊定義)洛波。它是一個(gè)在瀏覽器端模塊化開發(fā)的規(guī)范。它不是javascript原生支持骚露,所以使用AMD規(guī)范進(jìn)行頁(yè)面開發(fā)需要用到對(duì)應(yīng)的庫(kù)蹬挤,也就是RequireJS,AMD其實(shí)是RequireJS在推廣的過程中對(duì)模塊定義的范圍化的產(chǎn)出棘幸。
它的實(shí)現(xiàn)方案是:先定義所有依賴焰扳,然后在加載完成后的回調(diào)函數(shù)中執(zhí)行。
AMD是預(yù)加載, 只有一個(gè)接口:define(id?,dependencies?,factory);?它要在聲明模塊的時(shí)候制定所有的依賴(dep)误续,并且還要當(dāng)做形參傳到factory中吨悍,注意的是這些依賴文件并沒有書寫順序的區(qū)別;
但是開始就把所有依賴寫出來(lái)是不符合書寫的邏輯順序的蹋嵌,能不能像commonJS那樣用的時(shí)候再require育瓜,而且還支持異步加載后再執(zhí)行呢?
優(yōu)點(diǎn):
適合在瀏覽器環(huán)境中異步加載模塊
可以并行加載多個(gè)模塊
缺點(diǎn):
提高了開發(fā)成本栽烂,代碼的閱讀和書寫比較困難躏仇,模塊定義方式的語(yǔ)義不順暢
不符合通用的模塊化思維方式,是一種妥協(xié)的實(shí)現(xiàn)
三腺办、CMD
CMD是另一種js模塊化方案焰手,它與AMD很類似,不同點(diǎn)在于:AMD 推崇依賴前置怀喉、提前執(zhí)行册倒,CMD推崇依賴就近、延遲執(zhí)行磺送。
Common Module Definition(CMD),??是seajs推崇的規(guī)范驻子,CMD則是依賴就近,用的時(shí)候再require估灿。CMD 推崇 as lazy as possible(盡可能的懶加載崇呵,也稱為延遲加載,即在需要的時(shí)候才加載)馅袁。
AMD 和 CMD 的書寫區(qū)別:
AMD依賴前置域慷,在定義模塊時(shí)就聲明其所要依賴的模塊
CMD是按需加載依賴,在用到那個(gè)模塊再去require
AMD在使用前就準(zhǔn)備好汗销,CMD是用到了再去準(zhǔn)備模塊
優(yōu)點(diǎn):
1犹褒、依賴就近,延遲執(zhí)行
2弛针、可以很容易在 Node.js 中運(yùn)行
缺點(diǎn):依賴 SPM 打包叠骑,模塊的加載邏輯偏重
現(xiàn)在我們?cè)賮?lái)說說ES6標(biāo)準(zhǔn)的模塊化:
ES6靜態(tài)加載的設(shè)計(jì)思想,使得在編譯時(shí)就可以確定模塊的依賴關(guān)系削茁,以及輸入宙枷、輸出的變量。ES6則在語(yǔ)言層面上實(shí)現(xiàn)了模塊化茧跋,取代CommonJS慰丛、AMD、CMD成為服務(wù)端和瀏覽器端通用的模塊解決方案瘾杭。(CommonJS诅病、AMD、CMD運(yùn)行時(shí)確定依賴關(guān)系)
ES6模塊和CommonJS的區(qū)別
CommonJS模塊輸出是值的拷貝粥烁,ES6模塊輸出是值的引用(引用時(shí)可能修改到模塊的值)
CommonJS是運(yùn)行時(shí)加載贤笆,ES6模塊是編譯時(shí)加載
ES6 Module是ES6中規(guī)定的模塊體系,相比上面提到的規(guī)范页徐, ES6 Module有更多的優(yōu)勢(shì)苏潜,ES6模塊化的特點(diǎn):
靜態(tài)加載,編譯時(shí)確定依賴關(guān)系
1变勇、自動(dòng)運(yùn)行于嚴(yán)格模式之下
2恤左、export關(guān)鍵字導(dǎo)出
3、import關(guān)鍵字導(dǎo)入
4搀绣、同步飞袋、異步加載均可
CommonJS與ES6 Module的區(qū)別:
1、CommonJS模塊是運(yùn)行時(shí)加載链患,ES6 Module是編譯時(shí)輸出接口
2巧鸭、CommonJS加載的是整個(gè)模塊,將所有的接口全部加載進(jìn)來(lái)麻捻,ES6 Module可以單獨(dú)加載其中的某個(gè)接口纲仍;
3呀袱、CommonJS輸出是值的拷貝,ES6 Module輸出的是值的引用郑叠,被輸出模塊的內(nèi)部的改變會(huì)影響引用的改變夜赵;
4、CommonJS?this指向當(dāng)前模塊乡革,ES6 Module?this指向undefined;
優(yōu)點(diǎn):
容易進(jìn)行靜態(tài)分析
面向未來(lái)的 EcmaScript 標(biāo)準(zhǔn)
缺點(diǎn):
原生瀏覽器端還沒有實(shí)現(xiàn)該標(biāo)準(zhǔn)
全新的命令字寇僧,新版的 Node.js才支持
目前瀏覽器對(duì)ES6 Module兼容還不太好,我們平時(shí)在webpack中使用的export/import沸版,會(huì)經(jīng)過babel轉(zhuǎn)換為CommonJS規(guī)范嘁傀。
具體可以參考:潛入理解ES6-模塊化
? ? ? ? ? ? ? ? ? ? ? ? ?時(shí)光機(jī)-《說說require 和 import 的區(qū)別》