1.什么是模块?
指在程序设计中,为完成某一功能所需的一段程序或子程序;或指能由编译程序、装配程序等处理的独立程序单位;或指大型软件系统的一部分。 ----《百度百科》
2.JavaScript缺乏模块机制。
-> 薄弱的JavaScript规范:
(1)没有模块系统;
(2)标准库较少(对于I/O流,文件系统等常见需求没有标准API);
(3)没有标准接口(没有Web服务器或数据库之类的标准统一接口);
(4)缺乏包管理系统(使JavaScript应用中基本没有自动加载和安装依赖的能力);
-> CommonJS规范(大部分为草案):
(1)内容:模块 二进制 Buffer 字符集编码 I/O流 进程环境 文件系统 套接字 单元测试 Web服务器网关接口 包管理 ...
(2)目的:使用CommonJS API写出的应用可以具备跨宿主环境执行的能力。
-> CommonJS模块规范:
(1)【模块引用】:
var math = require('math'); // require()方法 -> 接受模块标识,并引入一个模块的API到当前上下文。
(2)【模块定义】:
require() 方法 -> 导入模块
exports() 方法 -> 导出当前模块的方法或变量(唯一的导出口) ----
|----> JS文件中
module对象 -> 存在于模块中,代表模块自身,拥有exports属性 ----
(3)【模块标识】:
传递给require()方法的参数,
必须符合小驼峰命名的字符串,
或以.、..开头的相对路径或绝对路径,
可以没有.js后缀。
->模块规范的意义:
“使用户可以在完全不必考虑变量污染的前提下,建立上下游的依赖关系。”
3.Node的模块实现
(1)模块引入的步骤:
A.【路径分析】(通过模块标识符):
-> 模块标识符的分类:
-> 核心模块,如http、fs、path等;
-> .或..开始的相对路径文件夹;
-> 以/开始的绝对路径文件模块;
-> 非路径形式的文件模块,如自定义的connect模块。
B.【文件定位】
-> 文件扩展名分析
-> 目录分析和包
C.【编译执行】
在Node中,每个文件模块都是一个对象,其定义如下:
function Module(id, parent) {
this.id = id;
this.exports = {};
this.parent = parent;
if (parent && parent.children) {
parent.children.push(this);
}
this.filename = null;
this.loaded = false;
this.children = [];
}
(2)模块分类:
A.核心模块 -- Node提供的模块 (仅需路径分析,加载速度快)
B.文件模块 -- 用户编写的模块(三步执行,加载速度较慢)
(3)模块的缓存加载:
无论是核心模块还是文件模块,require()方法对相同模块的二次加载都一律采用缓存优先的方式,这是第一优先级的。
4.Node核心模块
(1)JavaScript编写的核心模块(存放在lib目录下) -> 需转存为C/C++代码
*与文件模块的区别:
A. 获取源码的方式(核心模块是从内存中加载的)
B. 缓存执行结构的位置
(2)C/C++编写的核心模块(存放在src目录下)-> 统称为“內建模块”(buffer、crypto、evals、fs、os等模块)
优势:
A. 性能优于脚本语言
B. 被编译进二进制文件,一旦Node开始执行,他们被直接加载仅内存中,无需在做标识符定位、文件定位、编译等过程,直接就可以执行
內建模块的导出:
内建模块 -> 核心模块 -> 文件模块
5.包与NPM
包与NPM是将模块联系起来的一种机制。
模块 -> 一定程度上解决了变量依赖、依赖关系等代码组织性问题
包 -> 在模块的基础上进一步组织JavaScript代码
(1)包规范 -- 帮助Node解决依赖包安装的问题。
A. 包结构
包实际上是一个存档文件,即一个目录直接打包为.zip或tar.gz格式的文件,安装后解压还原为目录。
完全符合CommonJS规范的包目录应该包含如下这些文件。
package.json :包描述文件 -> name(包名),description(简介),version(版本号),keywords(关键词数组),maintainers(包维护者列表)
bin :用于存放可执行二进制文件目录
lib :用于存放JavaScript代码的目录
doc :用于存放文档目录
test :用于存放单元测试用例的代码
B. 包描述
用于表达非代码相关的信息,它是一个JSON格式的文件 -- package.json 位于包的根目录下,是包的重要组成部分。
NPM的所有行为斗鱼包描述文件的字段息息相关。
(2)NPM -- 包规范的一种实践,帮助完成了第三方模块的发布、安装和依赖等。
借助NPM,Node与第三方模块之间形成了很好的生态系统。
借助NPM,可以帮助用户快速安装和管理依赖包。
(3)安装包,引用包,发布包
安装包:$npm install express -> node_modules > express
引用包:require()
发布包:保存js文件 -> $npm init -> $npm adduser -> npm pulish <folder>
(4)NPM的潜在问题 -> 包质量与安全问题
6.前后端功用模块
前后端JavaScript分别搁置在HTTP的两端,他们扮演的角色并不同。
浏览器端的JavaScript需要经历从同一个服务器端分发到多个客户端执行 -> 瓶颈在于带宽 -> 需要网络加载代码(慢)
服务器端的JavaScript需要经历相同的代码需要多次执行 -> 瓶颈在于CPU和内存资源 -> 直接从磁盘中加载(块)
解决的方式 -> AMD规范 && CMD规范
AMD规范:
AMD规范是CommonJS模块的一个延伸。
define(id?, dependencies?, factory);
id : 模块id(可选)
dependencies : 依赖(可选)
factory : 实际的代码内容
CMD规范:
更接近CommonJS规范的定义。
define(factory)
在依赖部分,支持动态引入:
define(function(require, exports, module) {
// The module code goes here
});
require、exports和module通过形参传递给模块,在需要依赖模块时,随时调用require()引入。