Node基础知识
Node的特点
- 异步I/O
- 事件与回调函数
- 单线程
- 跨平台
使用Node的场景
- 前后端编程语言环境统一
- 高性能I/O用于实时应用
- 并行I/O可以更高效利用分布式环境,提升Web渲染能力
- 构建前端工具类的应用
模块机制
CommonJS模块机制
1.模块引用
- 使用require()方法,接受模块标识,以此引入一个模块的API到当前上下文中
var math = require('math');
复制代码
2.模块定义
- exports对象用于到处当前模块的方法或变量
- 在模块中,一个module对象就代表模块自身
// math.js
exports.add = function() {
var sum = 0, i = 0, args = arguments, l = args.length;
while(i < l) {
sum += args[i++];
}
return sum;
};
复制代码
3.模块标识
- 模块表示就是传递给require()方法的参数,必须符合小驼峰命名的字符串
Node的模块实现
1.Node中引入模块的3个步骤
- 路径分析
- 文件定位
- 编译执行 注:Node对引入过的模块会进行缓存,以减少二次引入时的开销。require方法对于相同模块的二次加载,均采用缓存优先的方式,而较文件模块而言,Node会优先执行核心模块的缓存检查。与前端浏览器缓存静态脚本不同的是,浏览器仅仅缓存文件,而Node缓存的是编译和执行之后的对象。
2.模块标识符
- 核心模块(Node提供的),如:http、fs、path等
- 以.或..开始的相对路径文件模块
- 以/开始的绝对路径文件模块
- 非路径形式的文件模块,如自定义的connect模块
3.模块路径
- 是Node在定位文件模块的具体文件时指定的查找策略,具体表现为一个路径组成的数组
- 这个数组包含 1)当前文件目录下的node_modules目录 2)父目录下的node_modules目录 3)父目录的父目录下的node_modules目录 4)沿路径向上逐级递归,直到根目录下的Node_modules目录
4.文件定位
- 若require()的标识符若不出现文件扩展名,Node将按照.js, .json, .node的顺序依次补足扩展名进行尝试
5.模块编译
- 每个文件模块都是一个对象
- 每个编译成功的模块都会将其文件路径所谓索引缓存在Module._cache对象上
- .js文件通过fs模块同步读取文件后编译执行
- .node文件通过dlopen()方法加载最后编译生成的文件
- .json文件通过fs模块同步读取文件后,用JSON.parse()解析后返回结果
console.log(require.extendsions);
{'.js': [Function], '.json': [Function], '.node': [Function]}
复制代码
- JavaScript模块的编译
- 在编译的过程中,Node对获取到的JavaScript文件内容进行了头尾包装,从而避免了污染全局环境
- 每个模块文件之间都进行了作用域的隔离
(function(exports, require, module, __filename, __dirname) {
var math = require('math');
exports.area = function(radius) {
return Math.PI * radius * radius;
}
}
复制代码
前后端共用模块
1.AMD
define(id?, dependencies?, factory);
复制代码
- AMD的模块id和依赖是可选的,但是必须在声明时指定;
- 通过define来明确定义一个模块可以进行作用域隔离
2.CMD
define(['dep1', 'dep2'], function(dep1, deps){
return function(){};
});
复制代码
- CMD支持动态引入依赖,无需再声明模块时就指定
- 兼容多种模块规范
var multipleModules = function(name, definition){
var hasDefine = typeof define === 'function';
var hasExports = typeof module !== 'undefined' && module.exports;
if(hasDefine) {
// AMD or CMD
define(definition);
} else if(hasExports) {
// Node模块
module.exports = definition();
} else {
// 将模块执行结果挂在window变量中
this[name]= definition();
}
}
复制代码