nodejs:深刻模塊化

一、什麼是模塊化

模塊化是將一個總體系統按特定規則劃分爲各個獨立的個體。好比計算機模塊化爲CPU、內存、電源、顯示器等等。模塊化是一個簡化複雜的過程,同時在模塊化後各個獨立的個體之間的協調處理將變得更加的重要。用來協調處理各個模塊之間的工做的部分稱之爲模塊管理,監管和調配各個模塊可以正常工做,並能處理意外錯誤。javascript

隨着模塊的數量增長,如何處理模塊顯得很是的重要,要保證各個模塊之間的工做不會過度耦合、不會致使模塊之間互相抵觸,還要保證好各個模塊之間的依賴關係。html

咱們熟悉的jquery插件就至關因而jquery的模塊化,這些模塊是掛載在系統主枝幹上的,也就是說命名了一個模塊a,那麼就不能再命名一個模塊a,不然的話會出現模塊覆蓋的問題。前端

爲了解決這種問題,一種隨時用隨時取的模塊思想誕生了,即便是在其餘語言中存在好久,如c#的useing等,以及常被人們津津樂道的class類。在js中,客戶端語言和服務器語言最大的區別就是,使用源代碼必須從服務器上下載下來,而後才能解釋運行。由於種種網絡緣由,並不能保證模塊可以正常的加載進來,如何加載模塊又能夠分紅兩類。java

二、模塊化分類

在js業界,模塊的加載分爲AMD、CMD兩類,它們都有本身的適合場合,尤爲是在服務端和客戶端之間。node

  • AMD:Asynchronous Module Definition,異步模塊規範。指在須要用到該模塊的時候,纔去加載模塊,是一個異步過程,經常使用於客戶端。由於這些模塊都是遠程文件,調用的時候花費時間不定。所以,在客戶端瀏覽器JS中推薦使用該AMD。
  • CMD:Common Module Definition,通用模塊規範。指在初始化的時候就加載須要用到的模塊,是一個同步過程,經常使用於服務端。由於這些模塊都是本地文件,調用的時候花費時間很是少。所以,在服務端JS中推薦使用CMD。

AMD、CMD的使用場合沒有硬性規定,各取所需,合適的就是最好的。jquery

在模塊規範上,就有着本質的區別,所以模塊化的過程也是不一樣的。git

  • AMD:一個define是一個模塊,同一個文件能夠是多個模塊。
  • CMD:一個文件就是一個模塊,多個文件集合是一個大模塊。

如:github

// AMD
    // 定義 module1 ,依賴 depend1 和 depend2
    define("module1", [" depend1", "depend2"], function (depend1, depend2) {
    	// depend1
    	// depend2
    });
     
    // 定義 module2 ,依賴 module1
    define("module2", ["module1"], function (module1) {
    	// module1
    });
     
    // CMD
    // 定義模塊爲文件名
    define(function (require, exports, module) {
    	// require
    	// exports
    	// module
    });

AMD和CMD的模塊定義很是的相似,都使用了define函數。不一樣的是,AMD模塊規範,在定義模塊的時候就既定了依賴模塊,而CMD模塊並未這麼作,模塊之間的依賴關係有額外的配置文件決定。npm

在前端JS框架中,遵循AMD的有requireJS,遵循CMD的有seajs,各具特點。json

三、單模塊文件

nodejs中的模塊化遵循CMD,但又有些不一樣。

// 新建一個計算圓周長、圓面積的模塊
     
    var pi = Math.PI;
     
    // 計算周長
    exports.perimeter = function (r) {
    	return 2 * pi * r;
    }
     
    // 計算面積
    exports.area = function (r) {
    	return pi * r * r;
    }

如上,定義了一個計算圓周長、圓面積的模塊,由於每個文件就是一個模塊,就不須要寫define函數了,直接寫出口exports便可。exports出口能夠是任何對象。如:

A、出口是字面量

// module.js
    // 模塊出口是字面量
    module.exports="I'm a module!";
     
    // index.js
    // 調用模塊
    var md = require("./module.js");
    md;

B、出口是對象

// module.js
    // 模塊出口是對象
    module.exports={
    	name:"yundanran",
    	love:"ming"
    };
     
    // index.js
    // 調用模塊
    var md = require("./module.js");
    md.name;
    md.love;

C、出口是類

// module.js
    function Animal(type){
    	this.type=type;
    }
     
    Animal.prototype.say=function(){
    	return "Animal type is "+this.type;
    }
     
    // 出口是一個類
    module.exports=Animal;
     
    // index.js
    // 模塊調用
    var Md = require("./module.js");
    var md = new Md("people");
    md.say();

D、出口是函數

// module.js
    exports.fn1 = function () {
    	return "fn1";
    }
     
    exports.fn2 = function () {
    	return "fn2";
    }
     
    // index.js
    var md = require("./module.js");
    md.fn1();
    md.fn2();

四、建立模塊包

由多個模塊文件組成的一個總體,稱之爲包(模塊包、package),這些模塊文件合做完成一個相對更大一點的功能,具備一些處理錯誤、異常的能力。在模塊包(文件夾)中約定包含:

  • 模塊包配置文件(package.json)必須放在頂層目錄。
  • 二進制文件必須在bin文件夾下。
  • JS文件必須在lib文件夾下。
  • 文檔必須在doc文件夾下。
  • 單元測試必須在test文件夾下。

新建一個包module1,用來計算圓柱體的面積和體積。新建文件、文件夾以下:

  • /node_modules/module1/
  • /node_modules/module1/lib/
  • /node_modules/module1/doc/
  • /node_modules/module1/test/
  • /node_modules/module1/index.js
  • /node_modules/module1/lib/index.js
  • /node_modules/module1/lib/circle.js
  • /node_modules/module1/lib/rect.js

lib/circle.js:

// 計算圓周長、面積的模塊
     
    var pi = Math.PI;
    module.exports = {
    	perimeter: function (r) {
    		return 2 * pi * r;
    	},
    	area: function (r) {
    		return pi * r * r;
    	}
    };

lib/rect.js:

// 計算矩形面積模塊
     
    module.exports = function (w, h) {
    	return w * h;
    }

lib/index.js:

// 計算圓柱面積、體積
     
    // 引用 circle 模塊
    var circle = require("./circle.js");
     
    // 引用 rect 模塊
    var rect = require("./rect.js");
     
    exports.area = function (r, h) {
    	return 2 * circle.area(r) + circle.perimeter(r) * h;
    }
     
    exports.volume = function (r, h) {
    	return circle.area(r) * h;
    }

index.js:

module.exports=require("./lib");
    // 至關於 module.exports=require("./lib/index.js");

而後,cd到該模塊文件夾,執行如下命令(關於nmp後續再說):

npm init

命令板會要求輸入模塊包的各類信息,最後在該包文件夾下生成package.json文件(/node_modules/module1/package.json)。package.json文件包含了模塊包的各類信息,其中name值就是引用包須要用的名稱。例package.json:

{
      "name": "module1",
      "version": "1.0.0",
      "description": "",
      "main": "index.js",
      "directories": {
        "doc": "doc",
        "test": "test"
      },
      "scripts": {
        "test": "test"
      },
      "author": "ydr.me",
      "license": "BSD-2-Clause"
    }

引用該模塊包,在/app3/index.js:

// 引用系統的 http 模塊
    var http = require("http");
     
    // 引用系統的 url 模塊
    var url = require("url");
     
    // 引用系統的 querystring 模塊
    var qs = require("querystring");
     
    // 引用自定義 module1 模塊,名稱即爲 package.json 裏的 name 值
    var module1 = require("module1");
     
    http.createServer(function (request, response) {
    	var query=qs.parse(url.parse(request.url).query);
    	var r = query.r;
    	var h = query.h;
     
    	if (r !== undefined && h !== undefined) {
    		write(response, "<h1>計算圓柱的面積和體積</h1>\
    		<p>半徑 => " + r + "</p>\
    		<p>高 => " + r + "</p>\
    		<p>面積 => " + module1.area(r,h) + "</p>\
    		<p>體積 => " + module1.volume(r,h) + "</p>");
    	} else {
    		write(response, "<h1>計算圓柱的面積和體積</h1>\
    		<p>請輸入圓柱的班級或高</p>");
    	}
     
    }).listen(2014);
     
    function write(response, text) {
    	response.writeHead(200, {
    		"content-type": "text/html"
    	});
    	response.write(text);
    	response.end();
    }

打開localhost:2014便可看到效果。

五、模塊路徑

A、直接使用模塊名稱

在nodejs中,引用一個模塊(包)名稱,遵循如下規範。如在/app3/index.js中引用test模塊包

var test = require("test");

系統依次搜尋如下路徑,直到找到爲止:

  1. /app3/node_modules/test.js
  2. /node_modules/test.js

若是是引用如下系統的核心模塊也能夠直接使用模塊名稱:

  • http:提供HTTP服務器功能。
  • url:解析URL。
  • fs:即filestream,與文件系統交互。
  • querystring:解析URL的查詢字符串。
  • child_process:新建子進程。
  • util:提供一系列實用小工具。
  • path:處理文件路徑。
  • crypto:提供加密和解密功能,基本上是對OpenSSL的包裝。

B、標明模塊路徑

  • ./ => 當前路徑
  • ../ => 上層路徑
  • / => 根路徑

如:

// 引用同級目錄的test.js
    var test = require("./test.js");
     
    // 引用上級目錄的test.js
    var test = require("../test.js");
     
    // 引用根級目錄的test.js
    var test = require("/test.js");

六、參考資料

https://github.com/amdjs/amdjs-api/wiki/AMD

https://github.com/cmdjs/specification/blob/master/draft/module.md

http://requirejs.org/

http://seajs.org/

http://wiki.commonjs.org/wiki/Packages

http://nodejs.org/api/modules.html

相關文章
相關標籤/搜索