概述nodejs模塊系統核心原理

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

核心工做原理

模塊解析過程(Module Resolve)

test.jsnode

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:json

  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'模式,防止定義全局變量app

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

緩存(Cache)

在一個node上下文環境中,兩次require同一個文件,一般狀況下返回徹底相同的兩個對象引用。除非用高階函數返回工廠函數。模塊化

循環引用(Cycle)

因爲node包相互依賴,則較大可能會造成循環引用,node利用其緩存機制避免無限循環。好比函數

index.jsui

const prefix = '主模塊:'
const a = require('./a.js')

console.log(prefix, a)  // {a:2}
console.log(prefix, require.main === module)
console.log(module)
複製代碼

a.jsspa

'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引用

相關文章
相關標籤/搜索