深入浅出node(2) 模块机制
一) CommonJs 在 CommonJs 的官网上写着这样一句话 javascript:not just for browsers any more CommonJs 是一种规范,它涵盖了模块. 二进制. Buffer. 文件系统. 包管理等, node 就是借鉴了 CommonJs 的 Modules 规范实现了一套非常易用的模块系统
1.1 CommonJs 模块的定义 主要分模块引用. 模块定义. 模块标识 CommonJs 的模块导入导出机制可以使用户不必考虑变量污染等问题
- /*模块引入*/
- var math = require("math"); /*模块标识 传递给require的参数*/
- /*模块定义*/
- exports.add = function(a,b) {
- return a + b;
- }
-
二)Node 的模块实现 在 Node 中对规范进行了一定的取舍, 也增加了一定自身需要的特性 node 中引入模块主要分为 3 个步骤
- 路径分析
- 文件定位
- 编译执行
2.1 Node 中的模块分类 在 node 中模块分为两类 Node 提供的模块, 核心模块. 用户编写的模块, 文件模块
- 核心模块 在 node 的源代码编译的过程中被编译进了二进制执行文件, 在 node 进程启动的时候,部分的核心模块被直接加载到内存, 所以引用这部分模块不需要文件的定位和编译执行,并且在路径分析中优先判断,所以加载速度最快
- 文件模块 运行时动态的加载,需要完成的路径解析, 文件定位, 编译执行过程, 加载速度相对较慢
无论是核心还是文件模块 Node 都会采用缓存优先的策略, 不同于浏览器中缓存的是文件, Node 中缓存的是编译和执行之后的对象
2.2 路径分析和文件定位
2.2.1 路径分析 node 中根据 require() 中传入的标识符, 来进行模块的查找和定位, 对不同类型的标识符查找定位的方式会有一些区别 标识符只要分为下面几类
- 核心模块 (核心模块的优先级的优先级仅次于缓存加载, 在 Node 的源代码的编译过程中已经被编译成了二进制的代码, 加载过程最快 无法加载与核心模块相同标识符的自定义模块, 只能通过其他的方式加载与核心模块相同标识符的自定义模块)
- 绝对路径或者相对路径的文件模块 (通过将相对路径和绝对路径转换成真实路径, 并且以真实路径作为索引, 将编译后的结果放到缓存中, 由于指明了确切的文件位置, 所以其加载速度慢于核心模块)
- 非路径形式的文件模块, 通常为自定义模块 (当前文件目录下的 node_modules 父目录下的 node_modules 父目录的父目录下的 node_modules 沿路径向上逐级递归, 直到根目录的 node_modules 很像原型链的查找 所以自定义模块的查找速度最慢)
2.2.2 文件定位
- 文件的扩展名分析 CommonJs 中允许在标识符中不包含扩展名, 这种情况下 Node 会按照. js,.node,.json 的次序补足扩展名 在 require 的时候,是同步阻塞的判断文件是否存在的, 此时加入你确定需求的文件的扩展名字是. node,.json, 在 require 的时候补足扩展名, 能加快一下访问速度
- 目录分析和包 如果你通过 require() 的标示符查找到一个目录, Node 会将这个目录当做包处理 Node 会在当前的目录下查找 package.json 文件, 通过 JSON.parse() 解析出包描述对象, 从中读取出 main 属性执行的文件进行定位, 如果该文件不存在扩展名, 则进入扩展名解析的步骤 如果 main 执行的文件错误或者不存在 package.json 文件, Node 会将 index 当做默认的扩展名, 然后依次的查找 index.js,index.json,index.json
- 如果在通过上面的方式仍然没有定位到相应的文件或者模块, 则上升到下一个模块路径进行查找
2.3 模块编译
来源: