多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

中國最全IT社區平臺 聯系我們 | 收藏本站
阿里云優惠2

nodejs教程

Node.js 模塊

閱讀 (2314)

模塊

穩定性: 5 - 鎖定

Node 有簡單的模塊加載系統。在 Node 里,文件和模塊是一一對應的。下面例子里,foo.js 加載同一個文件夾里的 circle.js 模塊。

foo.js 內容:

var circle = require('./circle.js');
console.log( 'The area of a circle of radius 4 is '
           + circle.area(4));

circle.js 內容:

var PI = Math.PI;

exports.area = function (r) {
  return PI * r * r;
};

exports.circumference = function (r) {
  return 2 * PI * r;
};

circle.js 模塊輸出了 area()circumference() 函數。想要給根模塊添加函數和對象,你可以將他們添加到特定的 exports 對象。

加載到模塊里的變量是私有的,仿佛模塊是包含在一個函數里。在這個例子里, PIcircle.js 的私有變量。

如果你想模塊里的根像一個函數一樣的輸出(比如 構造函數),或者你想輸出一個完整對象,那就分派給 module.exports,而不是 exports

bar.js 使用 square 模塊, 它輸出了構造函數:

var square = require('./square.js');
var mySquare = square(2);
console.log('The area of my square is ' + mySquare.area());

square 定義在 square.js 文件里:

// assigning to exports will not modify module, must use module.exports
module.exports = function(width) {
  return {
    area: function() {
      return width * width;
    }
  };
}

模塊系統在 require("module") 模塊里實現。

Cycles

環形調用 require() ,當返回時模塊可能都沒執行結束。

考慮以下場景:

a.js:

console.log('a starting');
exports.done = false;
var b = require('./b.js');
console.log('in a, b.done = %j', b.done);
exports.done = true;
console.log('a done');

b.js:

console.log('b starting');
exports.done = false;
var a = require('./a.js');
console.log('in b, a.done = %j', a.done);
exports.done = true;
console.log('b done');

main.js:

console.log('main starting');
var a = require('./a.js');
var b = require('./b.js');
console.log('in main, a.done=%j, b.done=%j', a.done, b.done);

main.js 加載 a.jsa.js加載 b.js。此時,b.js試著加載 a.js。為了阻止循環調用,a.js輸出對象的不完全拷貝返回給b.js 模塊。 b.js 會結束加載,并且它的exports 對象提供給 a.js 模塊。

main.js加載完兩個模塊時,它們都會結束。這個程序的輸出如下:

$ node main.js
main starting
a starting
b starting
in b, a.done = false
b done
in a, b.done = true
a done
in main, a.done=true, b.done=true

如果你的程序有環形模塊依賴,需要保證是線性的。

核心模塊

Node 有很多模塊編譯成二進制。這些模塊在本文檔的其他地方有更詳細的描述。

核心模塊定義在 Node 的源代碼 lib/ 目錄里。

require() 總是會優先加載核心模塊。例如,require('http') 總是返回編譯好的 HTTP 模塊,而不管這個文件的名字。

文件模塊

如果按照文件名沒有找到模塊,那么 Node 會試著加載添加了后綴 .js, .json 的文件,如果還沒好到,再試著加載添加了后綴.node 的文件。

.js 會解析為 JavaScript 的文本文件, .json 會解析為 JSON 文本文件,.node 會解析為編譯過的插件模塊,由 dlopen 負責加載。

模塊的前綴'/' 表示絕對路徑。例如 require('/home/marco/foo.js') 將會加載 /home/marco/foo.js文件。

模塊的前綴'./' 表示相對于調用 require()的路徑。就是說,circle.js必須和 foo.js 在 同一個目錄里,require('./circle') 才能找到。

文件前沒有 /./ 前綴,表示模塊可能是 core module,或者已經從 node_modules 文件夾里加載過了。

如果指定的路徑不存在,require()將會拋出一個 code 屬性為 'MODULE_NOT_FOUND' 的異常。

node_modules 目錄里加載

如傳遞給 require() 的模塊不是一個本地模塊,并且不以 '/', '../', 或 './' 開頭,那么 Node 會從當前模塊的父目錄開始,嘗試在它的 node_modules 文件夾里加載模塊。

如果沒有找到,那么會到父目錄,直到到文件系統的根目錄里找。

例如,如果 '/home/ry/projects/foo.js' 里的文件加載 require('bar.js'),那么 Node 將會按照下面的順序查找:

  • /home/ry/projects/node_modules/bar.js
  • /home/ry/node_modules/bar.js
  • /home/node_modules/bar.js
  • /node_modules/bar.js

這樣允許程序獨立,不會產生沖突。

可以請求指定的文件或分布子目錄里的模塊,在模塊名后添加路徑后綴。例如,require('example-module/path/to/file') 會解決 path/to/file 相對于example-module 的加載位置。路徑后綴使用相同語法。

文件夾作為模塊

可以把程序和庫放到獨立的文件夾里,并提供單一的入口指向他們。有三種方法可以將文件夾作為參數傳給 require()

第一個方法是,在文件夾的根創建一個 package.json 文件,它指定了 main 模塊。package.json 的例子如下:

{ "name" : "some-library",
  "main" : "./lib/some-library.js" }

如果這是在 ./some-library 里的文件夾,require('./some-library') 將會試著加載 ./some-library/lib/some-library.js

如果文件夾里沒有 package.json 文件,Node 會試著加載 index.jsindex.node 文件。例如,如果上面的例子里沒有 package.json 文件。那么 require('./some-library') 將會試著加載:

  • ./some-library/index.js
  • ./some-library/index.node

緩存

模塊第一次加載后會被被緩存。這就是說,每次調用 require('foo') 都會返回同一個對象,當然,必須每次都要解析到同一個文件。

多次調用 require('foo') 也許不會導致模塊代碼多次執行。這是很重要的特性,這樣就可以返回 "partially done" 對象,允許加載過渡性的依賴關系,即使可能會引起環形調用。

如果你希望多次調用一個模塊,那么就輸出一個函數,然后調用這個函數。

模塊換成預警

模塊的緩存依賴于解析后的文件名。因此隨著調用位置的不同,模塊可能解析到不同的文件(例如,從 node_modules 文件夾加載)。如果解析為不同的文件,require('foo') 可能會返回不同的對象。

module 對象

  • {Object}

在每個模塊中,變量 module 是一個代表當前模塊的對象的引用。為了方便,module.exports 可以通過 exports 全局模塊訪問。module 不是事實上的全局對象,而是每個模塊內部的。

module.exports

  • {Object}

模塊系統創建 module.exports 對象。很多人希望自己的模塊是某個類的實例。因此,把將要導出的對象賦值給 module.exports。注意,將想要的對象賦值給 exports ,只是簡單的將它綁定到本地 exports 變量,這可能并不是你想要的。

例如,假設我們有一個模塊叫 a.js

var EventEmitter = require('events').EventEmitter;

module.exports = new EventEmitter();

// Do some work, and after some time emit
// the 'ready' event from the module itself.
setTimeout(function() {
  module.exports.emit('ready');
}, 1000);

另一個文件可以這么寫:

var a = require('./a');
a.on('ready', function() {
  console.log('module a is ready');
});

注意,賦給 module.exports 必須馬上執行,并且不能在回調中執行。

x.js:

setTimeout(function() {
  module.exports = { a: "hello" };
}, 0);

y.js:

var x = require('./x');
console.log(x.a);

exports alias

exports 變量在引用到 module.exports 的模塊里可用。和其他變量一樣,如果你給他賦一個新的值,它不再指向老的值。

為了展示這個特性,假設實現:require():

function require(...) {
  // ...
  function (module, exports) {
    // Your module code here
    exports = some_func;        // re-assigns exports, exports is no longer
                                // a shortcut, and nothing is exported.
    module.exports = some_func; // makes your module export 0
  } (module, module.exports);
  return module;
}

如果你對 exportsmodule.exports 間的關系感到迷糊,那就只用module.exports 就好。

module.require(id)

  • id {String}
  • 返回: {Object} 已經解析模塊的module.exports

module.require 方法提供了一種像 require() 一樣從最初的模塊加載一個模塊的方法。

為了能這樣做,你必須獲得module 對象的引用。require() 返回 module.exports,并且 module 是一個典型的只能在特定模塊作用域內有效的變量,如果要使用它,就必須明確的導出。

module.id

  • {String}

模塊的標識符。通常是完全解析的文件名。

module.filename

  • {String}

模塊完全解析的文件名。

module.loaded

  • {Boolean}

模塊是已經加載完畢,還是在加載中。

module.parent

  • {Module Object}

引入這個模塊的模塊。

module.children

  • {Array}

由這個模塊引入的模塊。

其他...

為了獲取即將用 require() 加載的準確文件名,可以使用 require.resolve() 函數。

綜上所述,下面用偽代碼的高級算法形式演示了 require.resolve 的工作流程:

require(X) from module at path Y
1. If X is a core module,
   a. return the core module
   b. STOP
2. If X begins with './' or '/' or '../'
   a. LOAD_AS_FILE(Y + X)
   b. LOAD_AS_DIRECTORY(Y + X)
3. LOAD_NODE_MODULES(X, dirname(Y))
4. THROW "not found"

LOAD_AS_FILE(X)
1. If X is a file, load X as JavaScript text.  STOP
2. If X.js is a file, load X.js as JavaScript text.  STOP
3. If X.json is a file, parse X.json to a JavaScript Object.  STOP
4. If X.node is a file, load X.node as binary addon.  STOP

LOAD_AS_DIRECTORY(X)
1. If X/package.json is a file,
   a. Parse X/package.json, and look for "main" field.
   b. let M = X + (json main field)
   c. LOAD_AS_FILE(M)
2. If X/index.js is a file, load X/index.js as JavaScript text.  STOP
3. If X/index.json is a file, parse X/index.json to a JavaScript object. STOP
4. If X/index.node is a file, load X/index.node as binary addon.  STOP

LOAD_NODE_MODULES(X, START)
1. let DIRS=NODE_MODULES_PATHS(START)
2. for each DIR in DIRS:
   a. LOAD_AS_FILE(DIR/X)
   b. LOAD_AS_DIRECTORY(DIR/X)

NODE_MODULES_PATHS(START)
1. let PARTS = path split(START)
2. let I = count of PARTS - 1
3. let DIRS = []
4. while I >= 0,
   a. if PARTS[I] = "node_modules" CONTINUE
   c. DIR = path join(PARTS[0 .. I] + "node_modules")
   b. DIRS = DIRS + DIR
   c. let I = I - 1
5. return DIRS

從全局文件夾加載

如果環境變量 NODE_PATH 設置為冒號分割的絕對路徑列表,并且在模塊在其他地方沒有找到,Node 將會搜索這些路徑。(注意,Windows 里,NODE_PATH用分號分割 )。

另外, Node 將會搜索這些路徑。

  • 1: $HOME/.node_modules
  • 2: $HOME/.node_libraries
  • 3: $PREFIX/lib/node

$HOME 是用戶的 home 文件夾,$PREFIX 是 Node 里配置的 node_prefix

這大多是歷史原因照成的。強烈建議將所以來的模塊放到 node_modules 文件夾里。這樣加載會更快。

訪問主模塊

當 Node 運行一個文件時, require.main 就會設置為它的 module。也就是說你可以通過測試判斷文件是否被直接運行。

require.main === module

對于 foo.js 文件。 如果直接運行 node foo.js,返回 true, 如果通過 require('./foo')是間接運行。

因為 module 提供了 filename 屬性(通常等于__filename),程序的入口點可以通過檢查 require.main.filename 來獲得。

附錄: 包管理技巧

Node 的 require() 函數語義定義的足夠通用,它能支持各種常規目錄結構。諸如 dpkg, rpm, 和 npm 包管理程序,不用修改就可以從 Node 模塊構建本地包。

下面我們介紹一個可行的目錄結構:

假設我們有一個文件夾 /usr/lib/node/<some-package>/<some-version>,包含指定版本的包內容。

一個包可以依賴于其他包。為了安裝包 foo,可能需要安裝特定版本的 bar 包。 bar 包可能有自己的包依賴,某些條件下,依賴關系可能會發生沖突或形成循環。

因為 Node 會查找他所加載的模塊的 realpath(也就是說會解析符號鏈接),然后按照上文描述的方式在 node_modules 目錄中尋找依賴關系,這種情形跟以下體系結構非常相像:

  • /usr/lib/node/foo/1.2.3/ - foo 包, version 1.2.3.
  • /usr/lib/node/bar/4.3.2/ - foo 依賴的 bar 包內容
  • /usr/lib/node/foo/1.2.3/node_modules/bar - 指向 /usr/lib/node/bar/4.3.2/ 的符號鏈接
  • /usr/lib/node/bar/4.3.2/node_modules/* - 指向 bar 包所依賴的包的符號鏈接

因此,即使存在循環依賴或依賴沖突,每個模塊還可以獲得他所依賴的包得可用版本。

foo 包里的代碼調用 foo ,將會獲得符號鏈接/usr/lib/node/foo/1.2.3/node_modules/bar 指向的版本。然后,當 bar 包中的代碼調用 require('queue'),將會獲得符號鏈接 /usr/lib/node/bar/4.3.2/node_modules/quux 指向的版本。

另外,為了讓模塊搜索更快些,不要將包直接放在 /usr/lib/node 目錄中,而是將它們放在 /usr/lib/node_modules/<name>/<version> 目錄中。 這樣在依賴的包找不到的情況下,就不會一直尋找 /usr/node_modules 目錄或 /node_modules 目錄了。基于調用 require() 的文件所在真實路徑,因此包本身可以放在任何位置。

為了讓 Node 模塊對 Node REPL 可用,可能需要將 /usr/lib/node_modules 文件夾路徑添加到環境變量 $NODE_PATH 。由于模塊查找 $NODE_PATH 文件夾都是相對路徑,因此包可以放到任何位置。

關閉
程序員人生
主站蜘蛛池模板: 欧美一级日韩在线观看 | 国产男女爽爽爽爽爽免费视频 | 在线高清国产 | 国产激情久久久久久影院 | 国产亚洲精品久久 | 国产欧美日韩综合精品一区二区三区 | 亚洲精品中文字幕乱码三区 | ppypp日本欧美一区二区 | 日本国产一区在线观看 | 女人18毛片视频一级毛片容 | 一区二区三区视频在线 | 色老头久久久久久久久久 | 欧美亚洲综合在线观看 | 欧洲一区| 精品女人 | 国产精品亚洲二区在线 | h视频免费高清在线观看 | 2022精品天堂在线视频 | 午夜男人天堂 | 福利视频美女国产精品 | 久久中国| 成人网在线观看 | h视频网站在线观看 | 一级毛片不卡 | 在线观看国产亚洲 | 色聚网久久综合 | 久草香蕉视频在线观看 | 久久久不卡国产精品一区二区 | аⅴ资源中文在线天堂 | 日韩色小说 | 欧美春色| 国产乱辈通伦影片在线播放 | 非洲黑人最猛性xxxx交 | 男女羞羞视频网站 | 免费看黄色的网站 | 精品国产一区二区三区免费 | 成人精品亚洲人成在线 | 日本日本 | 亚洲国产欧美在线不卡中文 | аⅴ成人天堂中文在线 | 欧美高清 hd video |