Node.js模塊機制採用了Commonjs規範,彌補了當前JavaScript開發大型沒有標準的缺陷,相似於Java中的類文件,Python中的import機制,NodeJs中能夠經過module.exports、require來導出和引入一個模塊.javascript
在模塊加載機制中,NodeJs採用了延遲加載的策略,只有在用到的狀況下,系統模塊纔會被加載,加載完成後會放到binding_cache中。java
推薦技術博客: Node.js技術棧node
require的加載機制?
,參考:模塊加載機制module.exports與exports的區別
,參考:module.exports與exports的區別假設有a.js、b.js兩個模塊相互引用,會有什麼問題?是否爲陷入死循環?
,參考:#a模塊中的undeclaredVariable變量在b.js中是否會被打印?
,參考:#C/C++模塊,也叫built-in內建模塊,通常用於native模塊調用,在require出去c++
native模塊,在開發中使用的Nodejs的http、buffer、fs等,底層也是調用的內建模塊(C/C++)。git
這裏非Nodejs自帶的模塊稱爲第三方模塊,其實還分爲路徑形式的文件模塊(以
.
、..
、/
開頭的)和自定義的模塊(好比express、koa框架、moment.js等)github
javaScript模塊:例如hello.js
面試
json模塊:例如hello.json
express
C/C++模塊:編譯以後擴展名爲.node的模塊,例如hello.node
json
├── benchmark 一些nodejs性能測試代碼 ├── deps nodejs依賴 ├── doc 文檔 ├── lib nodejs對外暴露的js模塊源碼 ├── src nodejs的c/c++源碼文件,內建模塊 ├── test 單元測試 ├── tools 編譯時用到的工具 ├── doc api文檔 ├── vcbuild.bat win平臺makefile文件 ├── node.gyp node-gyp構建編譯任務的配置文件 ...
面試中可能會問到能說下require的加載機制嗎?
api
在Nodejs中模塊加載通常會經歷3個步驟,路徑分析
、文件定位
、編譯執行
。
按照模塊的分類,按照如下順序進行優先加載:
系統緩存:模塊被執行以後會會進行緩存,首先是先進行緩存加載,判斷緩存中是否有值。
系統模塊:也就是原生模塊,這個優先級僅次於緩存加載,部分核心模塊已經被編譯成二進制,省略了路徑分析
、文件定位
,直接加載到了內存中,系統模塊定義在Node.js源碼的lib目錄下,能夠去查看。
文件模塊:優先加載.
、..
、/
開頭的,若是文件沒有加上擴展名,會依次按照.js
、.json
、.node
進行擴展名補足嘗試,那麼在嘗試的過程當中也是以同步阻塞模式來判斷文件是否存在,從性能優化的角度來看待,.json
、.node
最好仍是加上文件的擴展名。
目錄作爲模塊:這種狀況發生在文件模塊加載過程當中,也沒有找到,可是發現是一個目錄的狀況,這個時候會將這個目錄看成一個包
來處理,Node這塊採用了Commonjs規範,先會在項目根目錄查找package.json文件,取出文件中定義的main屬性("main": "lib/hello.js")
描述的入口文件進行加載,也沒加載到,則會拋出默認錯誤: Error: Cannot find module 'lib/hello.js'
node_modules目錄加載:對於系統模塊、路徑文件模塊都找不到,Node.js會從當前模塊的父目錄進行查找,直到系統的根目錄
假設有a.js、b.js兩個模塊相互引用,會有什麼問題?是否爲陷入死循環?看如下例子:
a.js
console.log('a模塊start');
exports.test = 1;
undeclaredVariable = 'a模塊未聲明變量'
const b = require('./b');
console.log('a模塊加載完畢: b.test值:',b.test);
複製代碼
b.js
console.log('b模塊start');
exports.test = 2;
const a = require('./a');
console.log('undeclaredVariable: ', undeclaredVariable);
console.log('b模塊加載完畢: a.test值:', a.test);
複製代碼
問題2: a模塊中的undeclaredVariable變量在b.js中是否會被打印?
控制檯執行node a.js
,查看輸出結果:
a模塊start
b模塊start
undeclaredVariable: a模塊未聲明變量
b模塊加載完畢: a.test值: 1
a模塊加載完畢: b.test值: 2
複製代碼
問題1,啓動a.js
的時候,會加載b.js
,那麼在b.js
中又加載了a.js
,可是此時a.js
模塊尚未執行完,返回的是一個a.js
模塊的exports
對象未完成的副本
給到b.js
模塊。而後b.js
完成加載以後將exports
對象提供給了a.js
模塊
問題2,由於undeclaredVariable
是一個未聲明的變量,也就是一個掛在全局的變量,那麼在其餘地方固然是能夠拿到的。
在執行代碼以前,Node.js會使用一個代碼封裝器進行封裝,例以下面所示:
(function(exports, require, module, __filename, __dirname) {
// 模塊的代碼
});
複製代碼
exports至關於module.exports 的快捷方式以下所示:
const exports = modules.exports;
複製代碼
可是要注意不能改變exports的指向,咱們能夠經過 exports.test = 'a'
這樣來導出一個對象, 可是不能向下面示例直接賦值,這樣會改變exports的指向
//錯誤的寫法 將會獲得undefined
exports = {
'a': 1,
'b': 2
}
//正確的寫法
modules.exports = {
'a': 1,
'b': 2
}
複製代碼
更好的理解之間的關係,能夠參考JavaScript中的對象引用
做者:五月君
連接:www.imooc.com/article/284…
來源:慕課網
Github: Node.js技術棧