Node.js - 模块加载机制

494 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第5天,点击查看活动详情

优先从缓存中加载

  • 模块在第一次加载后会被缓存,意味着多次调用 require() 方法不会导致模块的代码被多次执行
  • 注:不论是内置模块、用户自定义模块、还是三方模块,他们都会优先从缓存中加载,从而提高模块的加载效率

内置模块的加载机制

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

例如:在项目中,如果添加了第三方包,包名也叫 fs,那么通过 require('fs') 方法加载,始终返回的是内置的 fs 模块


自定义模块的加载机制

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

    // 加载自定义模块
    require('./customModule')
    
    // 会被识别为内置模块或第三方模块
    require('customModule')
    
  • 在使用 require() 方法加载自定义模块时,如果省略了文件的扩展名,则 Node.js 会按顺序分别尝试加载以下文件:

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

    • 补全 .js 扩展名进行加载

    • 补全 .json 扩展名进行加载

    • 补全 .node 扩展名进行加载

    • 加载失败,终端报错

  • 示例一

    Snip20220328_47.png

    • test 文件

      console.log("加载 test 文件")
      
    • test.js 文件

      console.log("加载 test.js 文件")
      
    • test.json 文件

      {
          "nam":"test.json"
      }
      
    • 在 demo.js 中加载 test

      const test = require('./test')
      console.log(test)
      
    • log

      加载 test 文件
      
  • 示例二

    Snip20220328_48.png

    • test.js 文件

      console.log("加载 test.js 文件")
      
    • test.json 文件

      {
          "nam":"test.json"
      }
      
    • 在 demo.js 中加载 test

      const test = require('./test')
      console.log(test)
      
    • log

      加载 test.js 文件
      
  • 示例三
    Snip20220328_49.png

    • test.json 文件

      {
          "nam":"test.json"
      }
      
    • 在 demo.js 中加载 test

      const test = require('./test')
      console.log(test)
      
    • log

      { nam: 'test.json' }
      

第三方模块的加载机制

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

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

  • 示例

    假设在 :\Users\test\project\foo.js 文件中调用 require('tools'),则 Node.js 会以以下顺序查找

    • \Users\test\project\node_modules\tools
    • \Users\test\node_modules\tools
    • \Users\node_modules\tools
    • \node_modules\tools
    • 加载失败,终端报错

目录作为模块

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

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

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

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

  • 示例验证一

    Snip20220328_45.png

    • testD 目录下的 package.json

      {
          "main": "./a.js"
      }
      
    • testD 目录下的 a.js

      console.log("通过 package.json 加载 a.js")
      
    • testD 目录下的 index.js

      console.log("加载 index.js")
      
    • 在 test.js 中的加载目录

      require("./testD")
      
    • log

      通过 package.json 加载 a.js
      
  • 示例验证二

    Snip20220328_46.png

    • testD 目录下的 a.js

      console.log("通过 package.json 加载 a.js")
      
    • testD 目录下的 index.js

      console.log("加载 index.js")
      
    • 在 test.js 中的加载目录

      require("./testD")
      
    • log

      加载 index.js