NodeJS -- 基础与模块机制

244 阅读3分钟

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]}
  1. 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支持动态引入依赖,无需再声明模块时就指定
  1. 兼容多种模块规范
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();
    }
}