7. NodeJs 之模块的加载机制

372 阅读3分钟

一、模块的加载机制

1. 优先从缓存中加载

console.log(222)

const express = require('express');

const app = express()

// 导入路由模块
const userRouter = require('./router')
// 注册路由
// app.use(userRouter)

// 给路由注册,并添加前缀
app.use('/api', userRouter)

app.listen(80, () => {
    console.log('running in http://127.0.0.1')
})

模块在第一次加载后会被缓存,这也意味着多次调用 require() 不会导致模块的代码被执行多次

注意:不论是内置模块、用户自定义模块、还是第三方模块,它们都会优先从缓存中加载,从而 提高模块的加载效率

image.png

2. 内置模块的加载机制

内置模块是由 Node.js 官方提供的模块,内置模块的加载优先级最高

例如require("fs") 始终返回内置的 fs 模块,即使在 node_modules 目录下有名字相同的包也叫 fs。

3. 自定义模块的加载机制

使用 require() 加载自定义模块时,必须指定以 ./ 或 ../ 开头的 路径标识符。在加载自定义模块时,如果没有指定 ./ 或 ../ 这样的标识符,则 node 会把它当作 内置模块第三方模块 进行加载。

同时,在使用 require() 导入自定义模块时,如果省略了文件的扩展名,则 Node.js 会 按 以下顺序 分别尝试加载以下的文件:

  1. 按照 确切的文件名 进行加载
  2. 补全 .js 扩展名 进行加载
  3. 补全 .json 扩展名 进行加载
  4. 补全 .node 扩展名 进行加载
  5. 以上都找不到,加载失败,终端报错。

按照 确切的文件名 进行加载

image.png

补全 .js 扩展名 进行加载

image.png

补全 .json 扩展名 进行加载

image.png

补全 .node 扩展名 进行加载

image.png

4. 第三方模块的加载机制

如果传递给 require() 的模块标识符不是一个内置模块,也没有以 ./ 或 ../ 开头,则 Node.js 会从当前模块的父目录开始,尝试从 /node_modules 文件夹中加载第三方模块。

如果没有找到对应的第三方模块,则会移动到再上一层父目录中,进行加载,直到文件系统的根目录

例如: 假设在 C:\workspace\other\project\code.js 文件里调用了 require('tools'), 则 Node.js 会按以下顺序查找:

  1. C:\workspace\other\project\node_modules\tools
  2. C:\workspace\other\node_modules\tools
  3. C:\workspace\node_modules\tools
  4. C:\node_modules\tools

5. 目录作为模块

当把 目录作为模块标识符,传递给 require() 进行加载的时候,有三种载方式:

  1. 在被加载的目录下查找一个叫做 package.json 的文件,并在这个 package.json 的文件 里 寻找 main 入口文件属性的值 ,作为 require() 加载的入口。

  2. 如果目录里没有 package.json 文件,或者 main 入口不存在或无法解析,则 Node.js 将会加载目录下的 index.js 文件

  3. 如果以上两步都失败了,则 Node.js 会在终端打印错误消息,报告模块的缺失: Error: cannot find module'xxx'

在被加载的目录下查找一个叫做 package.json 的文件,并在这个 package.json 的文件 里寻找 main 入口文件属性的值 ,作为 require() 加载的入口

image.png

如果目录里没有 package.json 文件,或者 main 入口不存在或无法解析,则 Node.js 将会加载目录下的 index.js 文件

image.png

image.png