天天看點

nodejs Module加載機制

Require加載module機制詳解

      • 加載檔案類型
      • 加載流程圖
      • 加載檔案詳細過程
      • 加載module詳細過程
      • 示例

加載檔案類型

node中的檔案和子產品是一一對應的。一個node.js檔案就是一個子產品,但是這個檔案可能是js代碼,JSON或者編譯過的C/C++拓展

加載流程圖

加載順序和流程如下圖所示,已經加載過的檔案會直接緩存起來,下次再require會直接從緩存加載。

nodejs Module加載機制

加載檔案詳細過程

  1. 如果 X 是内置子產品

    a. 傳回内置子產品

    b. 停止執行

  2. 如果 X 以 ‘/’ 開頭

    a. 設定 Y 為檔案根路徑

  3. 如果 X 以 ‘./’ 或 ‘/’ or ‘…/’ 開頭

    a. LOAD_AS_FILE(Y + X)

    b. LOAD_AS_DIRECTORY(Y + X)

  4. LOAD_NODE_MODULES(X, dirname(Y))
  5. 抛出異常 “not found”

LOAD_AS_FILE(X)

  • 如果 X 是一個檔案, 将 X 作為 JavaScript 文本載入并停止執行。
  • 如果 X.js 是一個檔案, 将 X.js 作為 JavaScript 文本載入并停止執行。
  • 如果 X.json 是一個檔案, 解析 X.json 為 JavaScript 對象并停止執行。
  • 如果 X.node 是一個檔案, 将 X.node 作為二進制插件載入并停止執行。

LOAD_AS_DIRECTORY(X)

  • 如果 X/package.json 是一個檔案,

    a. 解析 X/package.json, 并查找 “main” 字段。

    b. let M = X + (json main 字段)

    c. LOAD_AS_FILE(M)

    d. LOAD_INDEX(M)

  • LOAD_INDEX(X)

LOAD_INDEX(X)

  • 如果 X/index.js 是一個檔案, 将 X/index.js 作為 JavaScript 文本載入并停止執行。
  • 如果 X/index.json 是一個檔案, 解析 X/index.json 為 JavaScript 對象并停止執行。
  • 如果 X/index.node 是一個檔案, 将 X/index.node 作為二進制插件載入并停止執行。

加載module詳細過程

  • 查找目前目錄下面的node_modules目錄

    a. LOAD_AS_FILE(DIR/X)

    b. LOAD_AS_DIRECTORY(DIR/X)

  • 如果沒找到,再查詢父目錄的node_modules目錄,直到找到或者到了根目錄的node_modules目錄(待查詢目錄在module對象裡面的paths數組中)

示例

const demo1 = require('./demoModule/demo');
// ./demoModule/demo => console.log('demo file whitout .js')
// ./demoModule/demo.js => console.log('demo file whit .js')
const demo2 = require('./demoModule/demoWithJson');
// {
//     "memo": "this is json file"
// }
console.log(demo2.memo)
const demo3 = require('./demoModule/demoWithJS');
// ./demoModule/demoWithJS => console.log('demo file whit .js')
// ./demoModule/demoWithJS.json => 
// {
//     "memo": "this is demoWithJS.json"
// }
const demo4 = require('./demoModule');
// ./demoModule/index.js => console.log('this is index.js in demoModule')
const demo5 = require('./demoModule/dirWithPackage');
// ./demoModule/dirWithPackage/main.js => console.log('this is main.js in dirWithPackage')
// ./demoModule/dirWithPackage/package.json 裡面的main字段為“main.js”
// const demo6 = require('./demoModule/demoNode');
const demo7 = require('demo')
/*
./node_modules/demo/index.js
// 源碼:
console.log('this is index.js in node_modules/demo')
const subDemo = require('subdemo');
const subDemo2 = require('subdemo2');

// subdemo 和 subdemo2所在位置和源碼
  ./node_modules/demo/node_modules/subdemo/index.js
   => console.log('this is index.js in ./node_modules/demo/node_modules/subdemo') 
  ./node_modules/subdemo2/index.js
   => console.log('this is index.js in ./node_modules/subdemo2') 
*/

const demo8 = require('demo2')
// ./node_modules/demo2/index.js => console.log('this is index.js in ./node_modules/demo2')
// ./node_modules/demo2.js => console.log('this is demo2.js in ./node_modules')
const subDemo3 = require('subdemo3');
// ../node_modules/subdemo3/index.js
const subDemo4 = require('subdemo4');
// ../../node_modules/subdemo4/index.js
const subDemo5 = require('subdemo5');
// /Users/username/.node_modules/subdemo5.js
           

輸出結果

demo file whitout .js

this is json file

demo file whit .js

this is index.js in demoModule

this is main.js in dirWithPackage

this is index.js in node_modules/demo

this is index.js in node_modules/demo/node_modules/subdemo

this is index.js in node_modules/subdemo2

this is demo2.js in ./node_modules

this is index.js in …/node_modules/subdemo3

this is index.js in …/…/node_modules/subdemo4

this is subdemo5.js in /Users/lifugui/.node_modules

其實,module.paths 裡面已經包含了上述這些會去查找的目錄以及優先級

// 目前檔案目錄 /Users/username/Documents/projects/nodeDemo
[ 
  '/Users/username/Documents/projects/nodeDemo/repl/node_modules', // 這個目錄是幹嘛的?不清楚,實測并不會從這個目錄加載module
  '/Users/username/Documents/projects/nodeDemo/node_modules',
  '/Users/username/Documents/projects/node_modules',
  '/Users/username/Documents/node_modules',
  '/Users/username/node_modules',
  '/Users/node_modules',
  '/node_modules',
  '/Users/username/.node_modules', // 全局module 可以考慮放這兩個目錄
  '/Users/username/.node_libraries'
]
           

繼續閱讀