Nodejs模塊化 CommonJS規范


node.js模塊化&commonJS規范

nodejs與commonjs

nodejs主要用於服務端編程,文件一般都能夠本地讀取速度較快,采用的是同步加載的commonjs規范。

關於commonjs:

  • 每個文件都是封閉的一個模塊,模塊里定義的變量、函數、類都是私有的
  • module代表當前模塊,module是封閉的,但它的exports屬性向外提供調用接口
  • require加載模塊,讀取並執行一個js文件,然后返回該模塊的exports對象
  • commonjs是同步加載的,因此模塊加載的順序嚴格按照代碼書寫的順序執行
  • 模塊可以多次加載,但在第一次加載之后模塊會被編譯執行,放入緩存,后續的require直接從緩存里取值,模塊代碼不再編譯執行

require內部處理流程

  • 檢查Module._cache是否緩存了指定模塊
  • 如果緩存沒有的話,就創建一個新的module實例將它保存到緩存
  • module.load()加載指定模塊
  • 在解析的過程中如果發生異常,就從緩存中刪除該模塊
  • 返回該模塊的module.exports

模塊化導出方式

  • global.address = 'beijing';//導出全局變量,只要導入相應js文件即可調用
  • module.exports = "str";//可以
  • module.exports.msg = 'str'//可以
  • exports.msg = 'str'//可以
  • exports = 'str'//不行

關於最后一個導出方式為什么不行的說明:
module是封閉的模塊,屬性、函數都是私有的,僅對外提供module.exports屬性以供調用,而require加載函數的返回值永遠是module.exports屬性。
由於exports默認指向的是module.exports,如果采用exports={}的方式,exports不再指向module.exports.
因為exports引用關系改變不再指向module.exports,所以無法被require識別調用

模塊化原理

module的封閉性,模塊的隔離怎么實現?

利用JavaScript函數式編程的特性,采用自執行函數,以其局部作用域實現隔離。

模塊化的輸出怎么實現?

node在加載js文件之前先准備一個module對象
module{id:'jsfilename',exports:{}}
在加載的時候,把js文件加載進load函數,module作為load函數的形參傳進去,最后把js文件的對象保存在module.exports屬性中並返回
在require獲取module時,只要傳入對應的id找到對應的module,就可以在Node中拿到對應module的exports對象,完成模塊的輸入與輸出
代碼如下:

// 准備module對象:
var module = {
    id: 'hello',
    exports: {}
};
var load = function (module) {
    // 讀取的hello.js代碼:
    function greet(name) {
        console.log('Hello, ' + name + '!');
    }
    
    module.exports = greet;
    // hello.js代碼結束
    return module.exports;
};

var exported = load(module);
// 保存module:
save(module, exported);

案例

// a.js
exports.x = 'a1';
console.log('a.js ', require('./b.js').x);
exports.x = 'a2';

// b.js
exports.x = 'b1';
console.log('b.js ', require('./a.js').x); 
exports.x = 'b2';

// main.js
console.log('main.js ', require('./a.js').x);
console.log('main.js ', require('./b.js').x);

輸出: a1 b2 a2 b2
分析:
前提:commonjs模塊的加載是嚴格同步的且在第一次加載時編譯代碼並存入緩存,后續加載直接從緩存讀取

  • 執行main.js第一行,首次加載並執行a.js並將a加入緩存
  • a.js中require b.js,此時a被阻塞,需要等待b編譯加載並執行完成,此時a的緩存寫入了x為a1
  • b.js中require a,由於a的已經被main.js第一次加載,此刻讀取緩存中a的exports為a1
  • b.js打印a1,隨后b將x=b2寫入緩存,b首次加載完成,此時a.js等待完畢,將x=a2寫入緩存,a首次加載完畢
  • main.js中,a打印a編譯、加載完畢之后x的值,a2。main.js第二行,由於b.js已經存在於緩存中,於是直接從緩存中讀取x為b2並打印
  • 綜上,打印結果為a1,b2,a2,b2

Nodejs模塊

主要基於commonJS規范,包括內置模塊、自定義模塊、第三方模塊

內置模塊

node自身攜帶的模塊
例如:require('http');require('path');require('url');

自定義模塊

require函數的形參path中用相對路徑或者絕對路徑導入的模塊
在本地實現,通過module.exports導出

第三方模塊

主要是npm的一些開源的包,當然你也可以發布自己的包


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM