# 此页面贡献者:年轻的铲屎

CommonJS

CommonJS 规范,为 JavaScript 制定了一个美好的愿景——希望 JavaScript 能够在任何地方运行。

Node 中,模块分为 2 类:

  1. Node 提供的模块,称为核心模块

    核心模块在 Node 源代码的编译过程中已经编译为二进制代码。在 Node 进程启动时,部分核心模块就直接被加载进内存中。

  2. 用户编写的模块,称为文件模块

    在运行中动态加载。

CommonJS 的模块规范,主要分为 3 部分:

  1. 模块定义

    Node 中,一个文件就是一个 module 对象,该对象含有 exports 属性。通过 exports 导出当前模块的方法或变量。

  2. 模块引用

    通过 require() 方法接受 模块标识 来引入模块的 API 到当前上下文。

  3. 模块标识

    即传递给 require() 的参数。小骆峰命名字符串。可以没有文件后缀名。主要分为 4 类:

    • 核心模块 e.g. http fs path
    • ... 开始的相对路径文件模块
    • / 开始的绝对路径文件模块
    • 非路径形式的文件模块,如自定义的 connect 模块

Node 通过 require() 引入模块,需要经历 3 个步骤:

  1. 路径分析

    • 查找优先级 & 加载速度:核心模块 > 文件模块 > 自定义模块
  2. 文件定位

    • 文件扩展名分析,按以下次序补足扩展名: .js > .json > .node
    • 上一步扩展名分析没有查找到对应文件,则模块标识为目录,将目录视为包进行分析(自定义模块常见场景):
      • 查找目录下 package.jsonmain 字段,进行文件定位
      • 如果上一步失败,则默认 index 为文件名,并为其匹配查找扩展名
      • 如果上一步失败 again ,自定义模块进入下一个模块路径进行查找
      • 如果上一步失败 again ,抛出查找失败异常
  3. 编译执行

    • 定位到具体文件后, Node 新建模块对象,根据路径载入并编译。对不同文件扩展名,载入方法不同。如 .js 文件,通过 fs 模块同步读取文件后编译执行。成功编译的模块都会将其文件路径作为所以缓存在模块对象中。

相同模块的第二次加载都一律采用缓存优先的方式。不需要再次经历以上 3 个步骤

学习资料

深入浅出Node.js

require() 源码解读

上次更新: 7/29/2018, 12:21:27 PM