概述nodejs模塊系統核心原理

NO IMAGE
  • 核心工作原理
    • 模塊解析過程(Module Resolve)
    • 模塊對象(Module Object)
    • 模塊包裝(Module Wrapper)
    • 緩存(Cache)
    • 循環引用(Cycle)

核心工作原理

模塊解析過程(Module Resolve)

test.js

require('x')
  1. x是node核心模塊(如http,zlib等)則返回,否則繼續
  2. 根據Module對象的paths屬性一直遞歸找node_modules文件夾下是否存在該模塊,直到根目錄,否則拋出Error(‘MODULE_NOT_FOUND’)
  3. x是路徑(如/path/to/file)
    • 嘗試LOAD_AS_FILE(如.js,.json,.node),沒有則繼續
    • 嘗試LOAD_AS_DIR(如文件夾下package.json),沒有則拋出Error(‘MODULE_NOT_FOUND’)

LOAD_AS_FILE:

  1. .js
  2. .json
  3. .node文件(編譯好的二進制node插件)

LOAD_AS_DIR:

  1. X/package.json中的main字段作為模塊入口文件
  2. index.js
  3. index.json
  4. index.node

模塊對象

Module {
id: '.',
exports: {},
parent: null,
filename: '/Users/wl/Sites/myapp/node-learning/src/module/index.js',
loaded: false,
children:
[
Module
{
id: '/Users/wl/Sites/myapp/node-learning/src/module/a.js',
exports: [Object],
parent: [Circular],
filename: '/Users/wl/Sites/myapp/node-learning/src/module/a.js',
loaded: true,
children: [Array],
paths: [Array]
}
],
paths:
[
'/Users/wl/Sites/myapp/node-learning/src/module/node_modules',
'/Users/wl/Sites/myapp/node-learning/src/node_modules',
'/Users/wl/Sites/myapp/node-learning/node_modules',
'/Users/wl/Sites/myapp/node_modules',
'/Users/wl/Sites/node_modules',
'/Users/wl/node_modules',
'/Users/node_modules',
'/node_modules'
]
}
  • id 模塊id。通常為模塊文件絕對路徑,主模塊通常為.
  • exports 模塊導出對象。這裡的exports指的是module.exports
  • parent 父模塊。即被依賴模塊
  • filename 模塊文件名。通常與id相同
  • loaded 模塊加載狀態。是否已執行完成
  • children 子模塊。即依賴模塊
  • paths 模塊查找路徑數組。

模塊包裝(Module Wrapper)

主要由以下兩點考慮

  • 使模塊內定義的頂層變量限制在方法(也就是wrapper或者說模塊內部)級作用域中,防止汙染global環境

注:建議啟用’use strict’模式,防止定義全局變量

  • 傳入module, require有利於實現node模塊化機制
(function(exports, require, module, __filename, __dirname) {
// Module code
});

緩存(Cache)

在一個node上下文環境中,兩次require同一個文件,通常情況下返回完全相同的兩個對象引用。除非用高階函數返回工廠函數。

循環引用(Cycle)

由於node包相互依賴,則較大可能會形成循環引用,node利用其緩存機制避免無限循環。比如

index.js

const prefix = '主模塊:'
const a = require('./a.js')
console.log(prefix, a)  // {a:2}
console.log(prefix, require.main === module)
console.log(module)

a.js

'use strict'
const prefix = 'A模塊:'
module.exports = {a:1}
const b = require('./b.js')
console.log(prefix, b)  // {b:1}
module.exports = {a:2}
console.log(prefix, require.main === module)

b.js

const prefix = 'b模塊:'
module.exports = {b:1}
const a = require('./a.js')
console.log(prefix, a) // {a:1}
console.log(prefix, require.main === module)

如上。當b.js引用a.js時,為避免無限循環,a.js未完成的副本(我認為是require(‘./b.js’)之前的所有代碼,但是在官方文檔中未得到特別確切的表述)導出的對象被b.js引用

相關文章

快速排序js實現

SpringBoot如何通過SecurityContext緩存賬號密碼

平淡的秋招之路

深入理解Java中protected修飾符