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

相关文章
相关标签/搜索