MST

星途 面试题库

面试题:Node.js 中 require 方法加载模块的原理

请详细阐述 Node.js 里 require 方法加载模块的具体原理,包括模块查找路径规则以及模块缓存机制。
32.1万 热度难度
前端开发Node.js

知识考点

AI 面试

面试题答案

一键面试

require 方法加载模块原理

  1. 模块查找路径规则
    • 核心模块:Node.js 有一套内置的核心模块,如 httpfs 等。当使用 require('http') 这样的语句加载模块时,Node.js 会首先检查是否为核心模块。如果是,直接加载核心模块,无需在文件系统中查找。
    • 文件模块
      • 绝对路径:如果 require 的参数是以 / 开头(在 Unix 系统上)或盘符(如 C:\ 在 Windows 系统上)开头,Node.js 会将其视为绝对路径。例如 require('/home/user/myModule.js')require('C:\\Users\\user\\myModule.js'),直接按照此路径加载模块。
      • 相对路径:如果参数以 ./../ 开头,Node.js 会相对于调用 require 的文件所在目录进行查找。例如在 main.js 文件中有 require('./subModule.js'),则会在 main.js 所在目录查找 subModule.js 文件。如果找不到 .js 文件,Node.js 会尝试查找同名的 .json 文件(会将其解析为 JSON 对象),如果还找不到,再尝试查找同名的目录。如果找到同名目录,Node.js 会查找该目录下的 package.json 文件,看其中是否有 main 字段指定入口文件。如果没有 package.json 文件或 main 字段指定的文件不存在,则会查找该目录下的 index.js 文件。
      • 自定义模块路径:如果参数不是以 /./../ 开头,Node.js 会在 node_modules 目录中查找。Node.js 会从调用 require 的文件所在目录开始,逐级向上查找父目录中的 node_modules 目录,直到找到模块或者到达文件系统的根目录。例如在 project/src/moduleA.jsrequire('myModule'),Node.js 会首先查找 project/src/node_modules,如果没找到,再查找 project/node_modules,依此类推。如果模块是一个包(即包含 package.json 文件),package.json 中的 main 字段指定了入口文件。如果没有 package.json 文件,则会查找 index.js 文件。
  2. 模块缓存机制
    • 缓存目的:为了避免重复加载相同的模块,提高性能。
    • 缓存实现:Node.js 内部维护了一个缓存对象,每个模块在第一次被加载后,其导出的内容会被缓存起来。当后续再次 require 同一个模块时(根据模块标识符,即 require 的参数,模块标识符在解析路径后是唯一的),Node.js 首先会检查缓存。如果缓存中存在该模块,直接返回缓存中的导出内容,而不会再次执行模块的加载逻辑。
    • 缓存范围:缓存是按模块标识符和模块所在的上下文(模块作用域)来维护的。不同的模块作用域中即使 require 相同标识符的模块,也会有不同的缓存实例。例如在不同的文件中 require('myModule'),每个文件的模块作用域内都有自己独立的 myModule 缓存。不过,如果是通过符号链接或者相同文件路径引用同一个模块,在同一个进程内会共享缓存。