1.模塊與模塊化開發(fā)
- 模塊:實(shí)現(xiàn)特定功能的一組方法
- 模塊化開發(fā):隨著瀏覽器性能的提升,相關(guān)技術(shù)的進(jìn)步,前端項(xiàng)目變得越來越復(fù)雜。為了提高開發(fā)效率,人們將特定功能的方法/代碼放在一起,構(gòu)成模塊,方便在開發(fā)過程中復(fù)用,但是出現(xiàn)了很多問題:全局變量的使用沖突,函數(shù)命名沖突,依賴關(guān)系管理困難。為了解決上述問題,制定了規(guī)范來解決上述問題——CommonJS、AMD、CMD
2.CommonJS
- CommonJS是起源于服務(wù)器端模塊化開發(fā)的規(guī)范
- 定義模塊:一個(gè)單獨(dú)的文件就是一個(gè)模塊,每一個(gè)模塊都是一個(gè)單獨(dú)的作用域(在模塊內(nèi)部定義的變量,無法被其他模塊讀取,除非定義為global對象的屬性)
- 模塊輸出:模塊只有一個(gè)出口
module.exports對象,需要將模塊希望輸出的內(nèi)容放在該對象中 - 加載模塊:加載模塊使用require方法,該方法讀取一個(gè)文件并執(zhí)行,返回文件內(nèi)部的
module.exports對象
//模塊定義 myModel.js
var name = 'Byron';
function printName(){
console.log(name);
}
function printFullName(firstName){
console.log(firstName + name);
}
module.exports = {
printName: printName,
printFullName: printFullName
}
//加載模塊
var nameModule = require('./myModel.js');
nameModule.printName();
- 問題:加載模塊和操作模塊提供的變量和方法是同步的(上面第二段代碼),即操作模塊提供的變量和方法必須得等到加載模塊完成后才可以執(zhí)行。在服務(wù)器端,所有的模塊(js文件)都放在硬盤中,因此模塊的加載速度很快。但是在瀏覽器端,加載模塊需要向服務(wù)器發(fā)送請求,會受到網(wǎng)絡(luò)的影響。如果模塊的加載需要等很長時(shí)間,瀏覽器就會處于“假死”狀態(tài)。因此CommonJS只適用于服務(wù)器端,并不適用于瀏覽器端。
3.AMD
- AMD即 Asynchronous Module Definition,中文名為異步模塊定義。它是一個(gè)在瀏覽器端模塊化開發(fā)的規(guī)范
- 使用AMD規(guī)范進(jìn)行開發(fā)需要使用RequireJS
- requireJS主要解決兩個(gè)問題:
- js文件之間的依賴關(guān)系:被依賴的文件需要早于依賴它的文件加載到瀏覽器
- js加載的時(shí)候?yàn)g覽器會停止頁面渲染,加載文件越多,頁面失去響應(yīng)時(shí)間越長
- AMD是一個(gè)模塊一個(gè)文件嗎?
使用
- 定義模塊:requireJS定義了一個(gè)函數(shù) define,它是全局變量,用來定義模塊
define(id?, dependencies?, factory);
- id:可選參數(shù),用來定義模塊的標(biāo)識,如果沒有提供該參數(shù),默認(rèn)為該模塊對應(yīng)的腳本文件名(去掉拓展名)
- dependencies:是一個(gè)當(dāng)前模塊依賴的模塊名稱數(shù)組
- factory:工廠方法,模塊初始化要執(zhí)行的函數(shù)或?qū)ο?。如果為函?shù),它應(yīng)該只被執(zhí)行一次。如果是對象,此對象應(yīng)該為模塊的輸出值
- 加載和使用模塊:
require([module], callback);
1.[module],是一個(gè)數(shù)組,指定了要加載的模塊
2.callback,是加載成功之后的回調(diào)函數(shù)
- 例子:
require(['math'], function (math) {
math.add(2, 3);
});
console.log('hello world');
console.log()的執(zhí)行和模塊的加載是異步的,不會因?yàn)榈却K的加載而使瀏覽器“假死”
4.CMD
- CMD即 Common Module Definition,中文為通用模塊定義,它是一個(gè)在瀏覽器端模塊化開發(fā)的規(guī)范
- 使用CMD規(guī)范進(jìn)行開發(fā)需要使用SeaJS
- Sea.js推薦一個(gè)模塊一個(gè)文件
使用
- 定義模塊:requireJS定義了一個(gè)函數(shù) define,它是全局變量,用來定義模塊
define(id?, dependencies?, factory);
- id:可選(推薦不寫,默認(rèn)為文件名),用來定義模塊的標(biāo)識,通常用文件名作為模塊id
- dependencies:可選(推薦不寫),是一個(gè)當(dāng)前模塊依賴的模塊名稱數(shù)組(因?yàn)镃MD推崇依賴就近,因此一般不在此處指定)
- factory:
function(require, exports, module)-
require(id):require 是一個(gè)方法,接受模塊標(biāo)識作為唯一參數(shù),用來獲取其他模塊提供的接口 - exports 是一個(gè)對象,用來向外提供模塊接口
- module 是一個(gè)對象,上面存儲了與當(dāng)前模塊相關(guān)聯(lián)的一些屬性和方法
- 加載模塊
seajs.use([module], callback);
1.[module],是一個(gè)數(shù)組,指定了要加載的模塊
2.callback,是加載成功之后的回調(diào)函數(shù)
seajs.use(['./a', './b'], function(a, b) {
a.doSomething();
b.doSomething();
});
AMD和CMD
- 模塊定義時(shí)對依賴的處理不同:
- AMD推崇依賴前置,在定義模塊的時(shí)候就要聲明其依賴的模塊
- CMD推崇就近依賴,只有在用到某個(gè)模塊的時(shí)候再去require
- 對依賴模塊的執(zhí)行時(shí)機(jī)處理不同(同第一點(diǎn),換種表述方式):
- AMD依賴前置,js可以方便知道依賴模塊是誰,立即加載
- CMD就近依賴,需要使用把模塊變?yōu)樽址馕鲆槐椴胖酪蕾嚵四切┠K
- 模塊的加載就是異步的
- SeaJS和RequireJS可以完成相同的功能
r.js
盡管RequireJS和SeaJS解決了模塊化開發(fā)遇到的問題,但是又出現(xiàn)了新的問題:一個(gè)單獨(dú)的文件就是一個(gè)模塊,如果網(wǎng)頁功能復(fù)雜,大量的模塊意味著大量的請求,這不僅會增加服務(wù)器的壓力,而且會影響用戶體驗(yàn)(完全加載時(shí)間變長).為了解決這個(gè)問題,需要使用 r.js 來對模塊進(jìn)行打包和壓縮,這能有效減少請求和j文件大小.
練習(xí)
項(xiàng)目地址
預(yù)覽地址
(點(diǎn)擊加載需要后端支持,因此預(yù)覽效果無法實(shí)現(xiàn))