學習Node.js遇到2個模塊互相引用的問題,有點搞不清楚。我以爲這個模塊機制對於學習Node.js來講,搞清代碼執行順序來講,十分有必要。html
因此在讀了相關資料,並實踐以後,愉快的在這分享一下成果。node
先說結論: CommonJS中的作法時,一旦某個模塊被」循環引用「,也就是這個模塊沒有加載完,就進入了循環,因此原則是, 只exports已經執行的那部分,沒執行的不輸出。
若是沒看懂,不要緊。我第一遍也沒明白。可是看下這個例子就好理解啦~緩存
a.js
module.exports.done = false var b = require('./a.js') console.log(`在a模塊中,b.done=${b.done}`) module.exports.done = true console.log('a模塊執行完畢')
b.js
module.exports.done = false var b = require('./a.js') console.log(`在a模塊中,b.done=${b.done}`) module.exports.done = true console.log('a模塊執行完畢')
在終端執行模塊化
node a.js
下面咱們梳理代碼的執行過程。而後本身運行代碼驗證一下就好啦~學習
終端的結果
因此問題的關鍵,就是弄清楚,當a模塊還沒執行完成時,b模塊裏require a模塊的話,執會導出a模塊已經執行完成的部分。ui
上面的例子中,a模塊只執行了spa
module.exports.done = false
因此就導出了這個。code
那麼建議同窗們,試一下把require('./b.js')放到第一行,試試看執行結果會有什麼不一樣?htm
若是有同窗實踐後,仍是不理解的話,能夠看看參考資料裏阮一峯老師的文章,或者看一眼我這篇文章的第二個部分,也許缺乏一些CommonJS的其餘知識。對象
被緩存的模塊,能夠經過require.cache裏看到
// 簡單說,require只認module.exports, // 而初始化時 exports是module.exports的引用 exports = module.exports
關於CommonJS裏"循環引用"的解決方法 + 辦法1:module.exports = () => {const moduleDemo = require('./b.js')} 避免require時直接執行,使其延遲執行。 + 辦法2:把module.exports提到第一行,但不是萬能的,由於要導出的東西可能依賴文件下面的計算
每個模塊化方案,均可能會遇到"循環引用"的狀況,可是執行方式不同。
由於AMD和CMD規範未來會被淘汰,因此ES6和CommonJS更值得拿出來研究一下。
ES6的引入命令是import,例如
import {foo} from './some.js'
ES6引入foo時,不會執行./some.js,而是生成一個該模塊的引用,當須要用foo變量時,在到some模塊裏取值。
因此ES6是動態引用,不會緩存some.js,而是生成一個引用對象。
在import時不去加載。天然地,所謂"循環引用"也就不是問題了。