本篇文章主要介绍node的模块机制,例如模块的加载顺序,node的实现等基础知识。主要从以下几个方面来阐述:
(1)commonJS的规范:该规范主要规范js的一些后端模块化规则,其与w3c,ECMAScript构成一个繁荣的生态圈:
commonJS规范主要包括以下三个方面:a)模块引用:require('math');
b) 模块定义:模块中存在一个module对象,代表模块本身,exports对象用于导出当前模块的方法或者变量,exports是module的属性
//math.js
//导出一个函数
exports.add=function(num1,num2){ return num1+num2; };
//导出一个对象
var hello={};
module.exports=hello;
c)模块标识:传给require的参数,它可以是以. ..开头的相对路径,或者以/开始的绝对路径,或者一个没有后缀名字的js文件
(2)node的模块实现:在node中,引入一个模块需要经历三个步骤:路径分析,文件定位,编译执行。node中模块分为两种:核心模块(node提供的模块,在node源代码编译过程中 即为二进制可执行文件,放在内存中,前两步可以忽略,只有编译执行一步,加载速度最快),文件模块(用户自己编写的模块)。
注:node加载模块优先从缓存加载,然后才是核心模块,缓存的是编译执行之后的对象,且核心模块的缓存检查优先于文件模块的缓存检查。
①路径分析:require()标示符:
- 核心模块:不需要路径分析和文件定位,直接在内存中加载
- .或者..开始的相对路径文件模块:位置比较明确,require将其转为真实路径之后作为索引编译执行,并放到缓存中
- /开始的绝对路径模块:位置比较明确,require将其转为真实路径之后作为索引编译执行,并放到缓存中
- 非路径形式的文件模块:a)路径查找:在本目录下的node_modules目录下查询
- b)如果查不到,去父目录node_modules目录下查询,一直到根目录下查不到的话即抛出异常
②文件定位:如果require()里面不包含扩展名,node会按照.js .json .node过程去尝试补足,如果到最后都没找到,发现标示是一个目录,即把该目录当做一个包进行处理。会在得到的目录下面找package.json文件,解析内容找到main属性指定的文件名进行定位,如果找不到该文件,就会去找index.js index.json index.node等文件,如果定位失败,则进入下一个对应的模块路径中进行查找,如果最终失败, 会抛出查找失败异常
③模块编译:.js文件:通过fs模块同步读取文件后编译执行
.json文件:fs读取后JSON.parse()解析后返回exports
.node文件:c/c++扩展,通过dlopen()加载内存中的二进制文件
a)JavaScript文件:在编译过程中对JavaScript文件进行头尾包装,变成如下模样:
(function(exports,require,module,_filename,_dirname){ var math=require('math'); exports.area=function(){} })
b).node文件:不需要编译,因为是c/c++编译好的文件,只需要加载执行即可
c).json文件:直接JSON.parse()处理即可
(3)NPM与包
①npm常用命令:npm install express:本地安装一个包,可用require()引入
npm install express -g :全局安装一个包,可通过命令行使用
②局域npm:建立一个本地npm服务器,便于公司安全
③包结构:
package.json文件内容:dependencies:{依赖的模块}
main:模块文件定位地址,如果不存在则默认本目录下index系列文件
④发布一个包的流程:
编写模块:
初始化包描述文件package.json:npm init按照提示即可
注册包仓库账号:npm adduser按照提示即可
上传包:npm publish <folder>