一. Node JS遵循的是commonJS规范

    CommonJS模块规范定义十分简单,分为模块引用,模块定义,模块标识3个部分。

    1. 模块引用

    例如: const math = require(‘math’);
    通过require来引入所需模块。

    1. 模块定义

      1. exports.add = function() {
      2. const number = 0;
      3. return number
      4. }

      通过exports来暴露出自定义的模块。
      自定义模块的引用也是通过require来引用。

    2. 模块标识

    模块标识其实就是传递给require()的参数。
    例如: const math = require(‘math’);
    math就是一个模块表示你。

    二. Node模块的定义和使用十分简单,但是其中会经历几个步骤。

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

    在nodejs中的模块分为两类:一类是nodejs核心模块(http, fs, path…),二是用户编写的文件模块。

    (1)核心模块部分在nodejs源码编译过程中,编译进了二进制执行文件。在node启动时,部分核心模块就被加载进了内存中,所以这部分核心模块在引入中就少了文件定位和编译执行这两个步骤。并且在路径分析的时候优先判断,所以它的加载速度是最快的。

    (2)文件模块则是在运行时动态加载,需要完整的路径分析,文件定位,编译执行这三个步骤。所以它的加载速度要比核心模块慢。

    与浏览器的缓存静态脚本优化性能一样,nodejs也会在加载过的模块进行缓存,减少二次引入的开销。区别在于,浏览器缓存的是文件,而nodejs缓存的是编译和执行后的对象。

    不管是核心模块还是文件模块,二次引入的模块一律采用优先从缓存加载,不同的地方在于,核心模块的缓存检查优先于文件模块的缓存检查。

    模块加载优先级:
    缓存 > 核心模块 > 文件模块

    NodeJS模块依赖层级关系图:
    node模块依赖关系.png
    其中内建模块是由c/c++编写的,他通常不被用户直接调用,因为核心模块通常都封装了内建模块。