Node.js 中的模块机制

简介: Node.js 中的模块机制

CommonJS

  • 模块引用
var math = require('math');
  • 模块定义

    • 上下文提供 exports 对象用于导出当前模块的方法或者变量,并且是唯一导出的出口
    • 模块中,还存在一个 module 对象,代表模块自身, exports 是 module 的属性
    • Node 中,一个文件就是一个模块
// math.js
exports.add = function () {
  var sum = 0,
    i = 0,
    args = arguments,
    l = arguments.length;
    while (i < l) {
      sum += args[i++];
    }
    return sum;
};
  • 模块标识

    • 传递给 require() 的参数,必须是符合小驼峰命名的字符串,或者 以 ... 开头的相对路径 或 绝对路径,结尾可以没有文件名后缀

模块实现

  • 实现

    1. 路径分析
    2. 文件定位
    3. 编译执行
  • 分类

    • 核心模块,Node 提供(核心模块在 Node 源代码编译过程中,编译进了二进制执行文件,在 Node 进程启动时,部分核心模块就直接被加载进内存中,加载速度快)
    • 文件模块,用户编写(在运行时动态加载,需要完成的路径分析、文件定位、难以执行过程,加载速度慢)
  • 优先缓存加载
  • 路径分析和文件定位

    • 模块标识符分析

      • 核心模块,最快
      • 路径形式的文件模块,较慢
      • 自定义模块(如文件或包),查找费时,最慢
    • 文件定位

      • 文件扩展名分析(不含扩展名时,按.js.node.json 次序补足,加上扩展名会加快速度)
      • 目录分析和包

        • 没有找到对应文件但发现一个目,会按照包处理
  • 模块编译

    • .js文件 通过 fs 模块同步读取文件后编译执行
    • .node文件 C/C++ 编写的扩展文件,通过 dlopen() 方法加载最后编译生成的文件
    • .json文件 通过 fs 模块同步读取后,用 JSON.parse() 解析返回结果
    • 其余扩展名文件,都按 .js 文件载入
// 一个正常的 JavaScript 文件会被包装成如下
(function (exports, require, module, __filename, __dirname) {
  var math = require('math');
  exports.area = function (radius) {
    return Math.PI * radius * radius;
  };
});

包与 npm

  • 包结构

    • package.json 包描述文件
    • bin 用于存放可执行二进制文件的目录
    • lib 用于存放 JS 代码的目录
    • doc 用于存放文档的目录
    • test 用于存放单元测试的代码
  • 包描述文件与 NPM

    • CommonJS 为 package.json 定义的必需字段

      • name
      • description
      • version major.minor.revision 参考 semver.org
      • keywords
      • maintainers
      • contributors
      • bugs
      • licenses
      • repositories
      • dependencies
      • homepage
      • os
      • cpu
      • engine
      • builtin
      • directories
      • implements
      • scripts
    • npm 新增字段

      • author
      • bin
      • main
      • devDependencies

前后端共用模块

  • AMD (CommonJS 模块规范的一个延伸)
// define(id?, dependencies?, factory);
define(function() {
  var exports = {};
  exports.sayHello = function() {
    alert('Hello from module ', module.id);
  };
  return exports;
});
  • CMD 规范
// define(factory);
define(function(require, exports, module) {
  // The module code goes here
});
  • 兼容多种模块规范
;(function (name, definition) {
  // 检测上下文环境是否为 AMD 或 CMD
  var hasDefine = typeof define === 'function',
    // 检查上下文环境是否为 Node
    hasExports = typeof module !== 'undefined' && module.exports;
  
  if (hasDefine) {
    // AMD 环境或 CMD 环境
    define(definition)
  } else if (hasExports) {
    // 定义为普通 Node 模块
    module.exports = definition();
  } else {
    // 将模块的执行结果挂在 window 中
    this[name] = definition();
  }
})('hello', function() {
  var hello = function() {};
  return hello;
});
相关文章
|
24天前
|
JavaScript 数据可视化
JS如何优雅的实现模块自动滚动展示
【8月更文挑战第22天】JS如何优雅的实现模块自动滚动展示
17 1
JS如何优雅的实现模块自动滚动展示
|
11天前
Nest.js 实战 (十二):优雅地使用事件发布/订阅模块 Event Emitter
这篇文章介绍了在Nest.js构建应用时,如何通过事件/发布-订阅模式使应用程序更健壮、灵活、易于扩展,并简化服务间通信。文章主要围绕@nestjs/event-emitter模块展开,这是一个基于eventemitter2库的社区模块,提供了事件发布/订阅功能,使得实现事件驱动架构变得简单。文章还介绍了如何使用该模块,包括安装依赖、初始化模块、注册EventEmitterModule、使用装饰器简化监听等。最后总结,集成@nestjs/event-emitter模块可以提升应用程序的事件驱动能力,构建出更为松耦合、易扩展且高度灵活的系统架构,是构建现代、响应迅速且具有高度解耦特性的Nest.
|
17天前
|
缓存 JavaScript 前端开发
JavaScript模块化开发:ES6模块与CommonJs的对比与应用
JavaScript模块化开发:ES6模块与CommonJs的对比与应用
17 2
|
25天前
|
算法 JavaScript 前端开发
国标非对称加密:RSA算法、非对称特征、js还原、jsencrypt和rsa模块解析
国标非对称加密:RSA算法、非对称特征、js还原、jsencrypt和rsa模块解析
105 1
|
28天前
|
JavaScript 前端开发 算法
js 内存回收机制
【8月更文挑战第23天】js 内存回收机制
30 3
|
28天前
|
存储 JavaScript 前端开发
学习JavaScript 内存机制
【8月更文挑战第23天】学习JavaScript 内存机制
22 3
|
1月前
|
存储 缓存 JSON
Node.js有哪些模块系统
【8月更文挑战第12天】Node.js有哪些模块系统
32 3
|
1月前
|
算法 JavaScript 前端开发
对称加密算法解析:DES、AES及其在`pycryptodome` 和 `crypto-js` 模块中的应用
对称加密算法解析:DES、AES及其在`pycryptodome` 和 `crypto-js` 模块中的应用
88 1
|
20天前
|
JavaScript 中间件 开发者
深入浅出Node.js中间件机制
【8月更文挑战第31天】本文将带你领略Node.js中间件的奥秘,通过直观的案例分析,揭示其背后的设计哲学。你将学会如何运用中间件构建强大而灵活的后端应用,以及在面对复杂业务逻辑时如何保持代码的清晰与高效。
|
20天前
|
设计模式 JavaScript 中间件
深入浅出Node.js中间件机制
【8月更文挑战第31天】在Node.js的世界里,中间件如同魔法般存在,它让复杂的请求处理变得井然有序。本文将带你领略中间件的奥秘,从原理到实战,一步步揭开它的神秘面纱。你将学会如何运用中间件来构建强大而灵活的后端应用,就像拼乐高一样有趣。