好程序員web前端教程分享js中的模塊化二-創(chuàng)新互聯(lián)

好程序員web前端教程接下來降為大家繼續(xù)分享js中的模塊化知識
4.循環(huán)依賴
就是a依賴b,b依賴a,對于不同的規(guī)范也有不同的結(jié)果。
4.1CommonJS
對于node,每一個模塊的exports={done:false}表示一個模塊有沒有加載完畢,經(jīng)過一系列的加載最后全部都會變?yōu)閠rue。 同步,從上到下,只輸出已經(jīng)執(zhí)行的那部分代碼 首先,我們寫兩個js用node跑一下:
//a.js
console.log('a.js')
var b = require('./b.js')
console.log(1)
//b.js
console.log('b.js')
var a = require('./a.js')
console.log(2)

創(chuàng)新互聯(lián)建站于2013年成立,先為奇臺等服務(wù)建站,奇臺等地企業(yè),進行企業(yè)商務(wù)咨詢服務(wù)。為奇臺企業(yè)網(wǎng)站制作PC+手機+微官網(wǎng)三網(wǎng)同步一站式服務(wù)解決您的所有建站問題。

//根據(jù)他的特點,require一個文件的時候,馬上運行內(nèi)部的代碼,所以相當于
console.log('a.js')
console.log('b.js')
console.log(2)
console.log(1)
//輸出是a.js、b.js、2、1
復(fù)制代碼
加上export的時候:
//a.js
module.exports = {val:1}
var b = require('./b.js')
console.log(b.val)
module.exports = {val:2}
b.val = 3
console.log(b)

//b.js
module.exports = {val:1}
var a = require('./a.js')
console.log(a.val)
module.exports = {val:2}
a.val = 3
console.log(a)

//1.在a.js暴露出去一個對象module.exports = {val:1}
//2.require了b,來到b,運行b腳本
//3.b的第一行,把{val:1}暴露出去,引入剛剛a暴露的{val:1},打印a.val的結(jié)果肯定是1
//4.重新暴露一次,是{val:2},然后做了一件多余的事情,改a.val為3(反正是拷貝過的了怎么改都不會影響a.js),毫無疑問打印出{ val: 3 }
//5.回到a,繼續(xù)第三行,打印b.val,因為b暴露的值是2,打印2
//6.繼續(xù)再做一件無意義的事情,打印{ val: 3 }
復(fù)制代碼
解決辦法:代碼合理拆分
4.2ES6模塊
ES6模塊是輸出值的引用,是動態(tài)引用,等到要用的時候才用,因此可以完美實現(xiàn)相互依賴,在相互依賴的a.mjs和b.mjs,執(zhí)行a的時候,當發(fā)現(xiàn)import馬上進入b并執(zhí)行b的代碼。當在b發(fā)現(xiàn)了a的時候,已經(jīng)知道從a輸入了接口來到b的,不會回到a。但是在使用的過程中需要注意,變量的順序。
如果是單純的暴露一個基本數(shù)據(jù)類型,當然會報錯not defined。 因為函數(shù)聲明會變量提升,所以我們可以改成函數(shù)聲明(不能用函數(shù)表達式)
//a.mjs
import b from './b'
console.log(b())
function a(){return 'a'}
export default a
//b.mjs
import a from './a'
console.log(a())
function b(){return 'b'}
export default b
復(fù)制代碼
4.3 require
我們一般使用的時候,都是依賴注入,如果是有循環(huán)依賴,那么可以直接利用require解決
define('a',['b'],function(b){
//dosomething
});
define('b',['a'],function(a){
//dosomething
});
//為了解決循環(huán)依賴,在循環(huán)依賴發(fā)生的時候,引入require:
define('a',['b','require'],function(b,require){
//dosomething
require('b')
});
復(fù)制代碼
4.4 sea
循環(huán)依賴,一般就是這樣
//a.js
define(function(require, exports, module){
var b = require('./b.js');
//......
});
//b.js
define(function(require, exports, module){
var a = require('./a.js');
//......
});
復(fù)制代碼
而實際上,并沒有問題,因為sea自己解決了這個問題: 一個模塊有幾種狀態(tài):
'FETCHING': 模塊正在下載中 'FETCHED': 模塊已下載 'SAVED': 模塊信息已保存 'READY': 模塊的依賴項都已下載,等待編譯 'COMPILING':模塊正在編譯中 'COMPILED': 模塊已編譯
步驟:
?1.模塊a下載并且下載完成FETCHED
?2.編譯a模塊(執(zhí)行回調(diào)函數(shù))
?3.遇到了依賴b,b和自身沒有循環(huán)依賴,a變成SAVED
?4.模塊b下載并且下載完成FETCHED
?5.b遇到了依賴a,a是SAVED,和自身有循環(huán)依賴,b變成READY,編譯完成后變成COMPILED
?6.繼續(xù)回到a,執(zhí)行剩下的代碼,如果有其他依賴繼續(xù)重復(fù)上面步驟,如果所有的依賴都是READY,a變成READY
?7.繼續(xù)編譯,當a回調(diào)函數(shù)部分所有的代碼運行完畢,a變成COMPILED
對于所有的模塊相互依賴的通用的辦法,將相互依賴的部分抽取出來,放在一個中間件,利用發(fā)布訂閱模式解決
5.webpack是如何處理模塊化的
假設(shè)我們定義兩個js:app.js是主入口文件,a.js、b.js是app依賴文件,用的是COMMONJS規(guī)范 webpack首先會從入口模塊app.js開始,根據(jù)引入方法require把所有的模塊都讀取,然后寫在一個列表上:
var modules = {
'./b.js': generated_b,
'./a.js': generated_a,
'./app.js': generatedapp
}
復(fù)制代碼
'generated
'+name是一個IIFE,每個模塊的源代碼都在里面,不會暴露內(nèi)部的變量。比如對于沒有依賴其他模塊的a.js一般是這樣,沒有變化:
function generated_a(module, exports, webpack_require) {
// ...a的全部代碼
}
復(fù)制代碼
對于app.js則不一樣了:
function generated_app(module, exports, webpack_require) {
var a_imported_module = webpack_require('./a.js');
var b_imported_module =
webpack_require
('./b.js');
a_imported_module['inc']();
b_imported_module['inc']();
}
復(fù)制代碼
webpack_require就是require、exports、import這些的具體實現(xiàn),夠動態(tài)地載入模塊a、b,并且將結(jié)果返回給app
對于webpack_require,大概是這樣的流程
var installedModules = {};//保存已經(jīng)加載完成的模塊
function webpack_require(moduleId) {
if (installedModules[moduleId]) {//如果已經(jīng)加載完成直接返回
return installedModules[moduleId].exports;
}
var module = installedModules[moduleId] = {//如果是第一次加載,則記錄在表上
i: moduleId,
l: false,//沒有下載完成
exports: {}
};
//在模塊清單上面讀取對應(yīng)的路徑所對應(yīng)的文件,將模塊函數(shù)的調(diào)用對象綁定為module.exports,并返回
modules[moduleId].call(module.exports, module, module.exports,webpack_require);
module.l = true;//下載完成
return module.exports;
}
復(fù)制代碼
對于webpack打包后的文件,是一個龐大的IIFE,他的內(nèi)容大概是這樣子:
(function(modules) {
var installedModules = {};
function
webpack_require
(moduleId) { /.../}
webpack_require.m = modules;//所有的文件依賴列表
webpack_require
.c = installedModules;//已經(jīng)下載完成的列表
webpack_require.d = function(exports, name, getter) {//定義模塊對象的getter函數(shù)
if(!
webpack_require
.o(exports, name)) {
Object.defineProperty(exports, name, {
configurable: false,
enumerable: true,
get: getter
});
}
};
webpack_require.n = function(module) {//當和ES6模塊混用的時候的處理
var getter = module && module.
esModule ?//如果是ES6模塊用module.default
function getDefault() { return module['default']; } :
function getModuleExports() { return module; };//是COMMONJS則繼續(xù)用module
__webpack_require
.d(getter, 'a', getter);
return getter;
};
webpack_require.o = function(object, property) { //判斷是否有某種屬性(如exports)
return Object.prototype.hasOwnProperty.call(object, property);
};
webpack_require
.p = "";//默認路徑為當前
return webpack_require(webpack_require.s = 0);//讀取第一個模塊
})
/****/
//IIFE第二個括號部分
([
(function(module, exports, webpack_require) {
var a =
webpack_require
(1);
var b = __webpack_require__(2);
//模塊app代碼
}),

(function(module, exports, webpack_require) {
//模塊a代碼
module.exports = ...
}),
(function(module, exports,
webpack_require
) {
//模塊b代碼
module.exports = ...
})
]);
復(fù)制代碼
如果是ES6模塊,處理的方法也不一樣。還是假設(shè)我們定義兩個js:app.js是主入口文件,a.js、b.js是app依賴文件。
(function(modules) {
//前面這段是一樣的
})
([
(function(module, webpack_exports,webpack_require) {//入口模塊
Object.defineProperty(webpack_exports, "esModule", { value: true });
var __WEBPACK_IMPORTED_MODULE_0
m =webpack_require(1);
var
WEBPACK_IMPORTED_MODULE_1m = webpack_require(2);
Object(
WEBPACK_IMPORTED_MODULE_0
m["a"])();//用object包裹著,使得其他模塊export的內(nèi)容即使是基本數(shù)據(jù)類型,也要讓他變成一個引用類型
Object(
WEBPACK_IMPORTED_MODULE_1m["b"])();

}),
(function(module, webpack_exports,webpack_require) {
webpack_exports["a"] = a;//也就是export xxx
//....
}),
(function(module,
webpack_exports
, webpack_require) {
webpack_exports
["b"] = b;
//....
})
]);

另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)cdcxhl.cn,海內(nèi)外云服務(wù)器15元起步,三天無理由+7*72小時售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國服務(wù)器、虛擬主機、免備案服務(wù)器”等云主機租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡單易用、服務(wù)可用性高、性價比高”等特點與優(yōu)勢,專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場景需求。

新聞名稱:好程序員web前端教程分享js中的模塊化二-創(chuàng)新互聯(lián)
轉(zhuǎn)載來源:http://muchs.cn/article16/hehgg.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供關(guān)鍵詞優(yōu)化、網(wǎng)站內(nèi)鏈、網(wǎng)頁設(shè)計公司、網(wǎng)站策劃、網(wǎng)站營銷、企業(yè)建站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

搜索引擎優(yōu)化