优先从缓存加载
有3个js文件,main.js,a.js,b.js
main.js
require('./a')
require('./b')
a.js
console.log('a.js被加载了')
require('./b')
b.js
console.log('b.js被加载了')
当在node中执行main.js时,打印结果为'a.js被加载了' 'b.js被加载了'各打印一次
首先加载a.js,打印一次'a.js被加载了'。在a.js中又加载b.js,打印一次'b.js被加载了',然后回到main.js中,执行require('./b.js'),由于在a.js中已经加载过b.js了,优先从缓存中加载,所以这里不会重复加载,并不会再打印一次'b.js被加载了'。
main.js中的require('./b')只是为了 得到其中的接口对象 ,并不会重复执行里面的代码。
main.js
require('./a') const fn = require('./b') console.log(fn)
a.js
console.log('a.js被加载了') const fn = require('./b') console.log(fn)
b.js
console.log('b.js被加载了') module.exports = function () { console.log('b的方法') }
执行main.js,打印结果为
a.js被加载了
b.js被加载了
[Function]
[Function]
这样做的目的是为了避免重复加载,提高模块加载效率
判断模块标识
共有三种模块
- 核心模块
- 第三方模块
- 自己写的模块
路径形式的模块(自己写的模块)
一般以
./ (当前目录,不可省略)
../ (上一级目录,也不可省略)
/ 开头,首位的 / 表示的是当前文件模块所属磁盘的根路径,在MAC等不区分磁盘系统中表示根目录,这种方式几乎不用
或者绝对路径(几乎不用)
.js后缀名可以省略
非路径形式1(核心模块)
核心模块的本质也是文件,已经被编译至二进制中,我们只需要按照名字来加载即可。在github中搜索nodejs可以看到源码,核心模块代码都在lib文件夹中,其中有http.js,path.js等
非路径形式2(第三方模块)
以art-template模块为例
首先在目录中npm i art-template
通过require('包名')即可使用
require('art-template')
不可能有任何一个第三方包与核心模块的名字是一样的,这些包是不允许提交的
第三方包的查找机制
- 先找到当前文件所属目录中的node_modules目录
- node_modules/art-template
-
node_modules/art-template/package.json
-
node_modules/art-template/package.json中的main属性
- main属性中记录了第三方包的入口模块
- 之后加载使用第三方包
- 如果package.json不存在或者其中的main属性指向的文件不存在,则node会自动找当前目录的index.js。也就是index.js会作为一个默认备选项
- 如果以上任何一个条件都不成立,则会进入上一层的node_modules目录查找
- 如果上一层还没有,会继续向上查找,一直找到根目录。
- 如果都没有找到,会报错 can not find module xxx