nodejs中 require 方法的加载规则
require参数类型
- http、fs、path等,原生模块
- ./mod或../mod,相对路径的文件模块
- /pathtomodule/mod,绝对路径的文件模块
- mod,非原生模块的文件模块
在进入路径查找之前有必要描述一下module path这个Node.js中的概念。对于每一个被加载的文件模块,创建这个模块对象的时候,这个模块便会有一个paths属性,其值根据当前文件的路径计算得到。Node.js在编译js文件的过程中实际完成的步骤有对js文件内容进行头尾包装。以app.js为例,我们将其放在任意一个文件夹中,包装之后的app.js将会变成以下形式:
(function (exports, require, module, __filename, __dirname) {
console.log(module.paths);
});
在app.js中输入如下内容:
console.log(module.paths);
执行node module app.js命令,将得到以下的输出结果:
[ '/home/jackson/research/node_modules',
'/home/jackson/node_modules',
'/home/node_modules',
'/node_modules' ]
Windows下:
[ 'c:\\nodejs\\node_modules',
'c:\\node_modules' ]
可以看出module path的生成规则为:从当前文件目录开始查找node_modules目录;然后依次进入父目录,查找父目录下的node_modules目录;依次迭代,直到根目录下的node_modules目录。
除此之外还有一个全局module path,是当前node执行文件的相对目录(../../lib/node)。如果在环境变量中设置了HOME目录和NODE_PATH目录的话,整个路径还包含NODE_PATH和HOME目录下的.node_libraries与.node_modules。其最终值大致如下:
[NODE_PATH,HOME/.node_modules,HOME/.node_libraries,execPath/../../lib/node]
require方法中的文件查找策略(指内置模块和第三方模块):
1、从module path数组中取出第一个目录作为查找基准。
2、直接从目录中查找该文件,如果存在,则结束查找。如果不存在,则进行下一条查找。
3、尝试添加.js、.json、.node后缀后查找,如果存在文件,则结束查找。如果不存在,则进行下一条。
4、尝试将require的参数作为一个包来进行查找,读取目录下的package.json文件,取得main参数指定的文件。
5、尝试查找该文件,如果存在,则结束查找。如果不存在,则进行第3条查找。
6、如果继续失败,则取出module path数组中的下一个目录作为基准查找,循环第1至5个步骤。
7、如果继续失败,循环第1至6个步骤,直到module path中的最后一个值。
8、如果仍然失败,则抛出异常。
文件查找流程:
由于 Node.js 中存在 4 类模块(原生模块和3种文件模块),尽管 require 方法极其简单,但是内部的加载却是十分复杂的,其加载优先级也各自不同。如下图所示:

一、优先从文件模块缓存中加载
尽管原生模块与文件模块的优先级不同,但是都会优先从文件模块的缓存中加载已经存在的模块。
二、原生模块
原生模块的优先级仅次于文件模块缓存的优先级。require 方法在解析文件名之后,优先检查模块是否在原生模块列表中。
在实际开发过程中,如果你的文件和核心库文件同名,加载过程中是会直接忽略你的项目文件。
例如在server下有config.json,require("config")。
require具体的加载过程是:
(1)核心库中如果有config.js 会直接加载 忽略你的文件。
(2)如果没有会检查你的项目中是否有这个.js文件。
(3)如果没有才会去查询 .json 文件。
所以在开发过程中最好使用其相对路径指明具体文件。
当第三方的模块和内置模块同名时,内置模块将覆盖第三方同名模块。因此命名时需要注意不要和内置模块同名。
原生模块也有一个缓存区,同样也是优先从缓存区加载。如果缓存区没有被加载过,则调用原生模块的加载方式进行加载和执行。
原生模块的本质也是文件,原生模块文件已经被编译到了二进制文件中了,我们只需要按照名字来加载就可以了。如:
1、require(‘fs’)
2、require(‘http’)
三、路径形式的模块
我们说的路径形式的模块,其实就是加载自己写的JS文件,有四种方式可以加载
当文件模块缓存中不存在,而且不是原生模块的时候,Node.js 会解析 require 方法传入的参数,并从文件系统中加载实际的文件 。
var fooExports = require('./index') //相对路径,常用
var fooExports = require('../index') //相对路径,常用
var fooExports = require('/index') //根目录,不常用
var fooExports = require('D:/demo/index') //根目录,不常用
注意,这里忽略了扩展名“.js”,以下是对等的:
var myMod = require('./my_mod')
var myMod = require('./my_mod.js')
如果当前目录有my_mod.js和my_mod.json,则会优先加载 my_mod.js。
可以直接require一个目录,假设有一个目录名为folder,如:
var myMod = require('./folder')
此时,Node将搜索整个folder目录,Node会假设folder为一个包并试图找到包定义文件package.json。如果folder 目录里没有包含package.json文件,Node会假设默认主文件为index.js,即会加载index.js。如果index.js也不存在, 那么加载将失败。
假如目录结构如下:

package.json定义如下:
{
"name": "pack",
"main": "modA.js"
}
此时 require('./folder') 将返回模块modA.js。如果package.json不存在,那么将返回模块index.js。如果index.js也不存在,那么将发生载入异常。
如果foder同级目录还有folder.js和folder.json,同时folder目录下还有index.js,则require('./folder') 将返回folder.js中的内容,否则返回folder.json中的内容,否则会返回folder目录下index.js中的内容,最后才会返回modA.js中的内容。
四、第三方模块
凡是用到第三方模块,都必须通过 npm 来下载;
使用的时候就可以通过 require(‘包名’) 的方式来进行加载才可以使用;
不可能有任何一个第三方包和核心模块的名字是一样的。
既不是核心模块、也不是路径形式的模块,就是第三方模块。
如果模块名不是路径,也不是内置模块,Node将试图去当前目录的node_modules文件夹里搜索。如果当前目录的node_modules里没有找到,Node会从父目录的node_modules里搜索,这样递归下去直到根目录。
总结:
其实主要就是两种情况:
1、如果require中是名称,则说明搜索的是内置模块或者第三方模块,此时内置模块的优先级高于第三方模块;
2、如果require中是路径,则会按照自定义模块的规则查找。
nodejs中 require 方法的加载规则的更多相关文章
- JS window对象 返回前一个浏览的页面 back()方法,加载 history 列表中的前一个 URL。 语法: window.history.back();
返回前一个浏览的页面 back()方法,加载 history 列表中的前一个 URL. 语法: window.history.back(); 比如,返回前一个浏览的页面,代码如下: window.hi ...
- JS window对象 返回下一个浏览的页面 forward()方法,加载 history 列表中的下一个 URL。
返回下一个浏览的页面 forward()方法,加载 history 列表中的下一个 URL. 如果倒退之后,再想回到倒退之前浏览的页面,则可以使用forward()方法,代码如下: window.hi ...
- EF如何操作内存中的数据以及加载相关联表的数据:延迟加载、贪婪加载、显示加载
之前的EF Code First系列讲了那么多如何配置实体和数据库表的关系,显然配置只是辅助,使用EF操作数据库才是每天开发中都需要用的,这个系列讲讲如何使用EF操作数据库.老版本的EF主要是通过Ob ...
- 源码学习:一个express().get方法的加载与调用
刚刚接触express,它的中间件确实把我搞得头晕.get的回调中要不要加next?不加载还会执行下一个中间件么?给get指定'/'路径是不是所有以'/'开头的访问在没有确切匹配时都能执行?use件又 ...
- 解决网页中Waiting (TTFB)数据加载过慢的问题
解决网页中Waiting (TTFB)数据加载过慢的问题 最近做了一个网页,在本地测试良好,数据可以得到很快的反馈,但是当部署到云端Linux上时候,就会出现加载缓慢的问题.本地测试,得到数据大概3s ...
- 1.Sentinel源码分析—FlowRuleManager加载规则做了什么?
最近我很好奇在RPC中限流熔断降级要怎么做,hystrix已经1年多没有更新了,感觉要被遗弃的感觉,那么我就把眼光聚焦到了阿里的Sentinel,顺便学习一下阿里的源代码. 这一章我主要讲的是Flow ...
- nodejs(13)模块加载机制
模块加载机制 优先从缓存中加载 当一个模块初次被 require 的时候,会执行模块中的代码,当第二次加载相同模块的时候,会优先从缓存中查找,看有没有这样的一个模块! 好处:提高模块的加载速度:不需要 ...
- 在Unity3D的网络游戏中实现资源动态加载
用Unity3D制作基于web的网络游戏,不可避免的会用到一个技术-资源动态加载.比如想加载一个大场景的资源,不应该在游戏的开始让用户长时间等待全部资源的加载完毕.应该优先加载用户附近的场景资源,在游 ...
- 使用getScript()方法异步加载并执行js文件
使用getScript()方法异步加载并执行js文件 使用getScript()方法异步请求并执行服务器中的JavaScript格式的文件,它的调用格式如下所示: jQuery.getScript(u ...
随机推荐
- C#代码获取另一程序的错误提示,并关闭窗口。
A程序报错弹框如下: B程序捕捉到此错误消息,并关闭.B程序核心代码如下. private void timer_Click(object sender, EventArgs e) { //查找Mes ...
- 模仿抽奖转盘,并且用cookie记录历史次数
自己制作了一个模仿抽奖转盘的小游戏,代码比较简单,规则是只有三次抽奖机会,并且浏览器会记录抽奖的次数, 代码如下 <!DOCTYPE html> <html> <head ...
- cocos2dx[3.2](8) 数学类Vec2/Size/Rect
数学类Vec2.Size.Rect,是cocos2dx中比较常用的类. 比如设置图片位置,设置图片大小,两图片的碰撞检测等等. 比起2.x版本,在3.x中本质上其实没有太大的变化,主要的变化就是将全局 ...
- python学习之迭代器
4.5 迭代器 4.5.1 可迭代对象 **字面意思分析**:可以重复的迭代的实实在在的东西. list,dict(keys(),values(),items()),tuple,str,set,ran ...
- 跨域设置之corsheaders
安装 pip install django-cors-headers 注册应用 INSTALLED_APPS = ( ... 'corsheaders', ... ) 中间层设置 MIDDLEWARE ...
- C语言I博客作业12-学期总结
一.我学到的内容 二.我的收获 1. https://www.cnblogs.com/1076022899-lj/p/11576442.html 收获:第一次接触到C语言和PTA,第一次学习了博客园和 ...
- 爬取网易云音乐评论!python 爬虫入门实战(六)selenium 入门!
说到爬虫,第一时间可能就会想到网易云音乐的评论.网易云音乐评论里藏了许多宝藏,那么让我们一起学习如何用 python 挖宝藏吧! 既然是宝藏,肯定是用要用钥匙加密的.打开 Chrome 分析 Head ...
- js知识点——1
onload 事件会在页面或图像加载完成后立即发生. document.write("内容")将在加载页面时输出 内容可以是什么,可以是一个标签,它输出的文件不能自动换行: < ...
- eclipse 逆向生成hbm配置文件及pojo
1.eclipse配置hibernate环境 由于在公司中不能在线安装jboss Tools,只能简单介绍手动安装 在jboss官网下载对应自己eclipse的压缩包. 在eclipse 中选择Hel ...
- python pycharm 注册码
D87IQPUU3Q-eyJsaWNlbnNlSWQiOiJEODdJUVBVVTNRIiwibGljZW5zZWVOYW1lIjoiTnNzIEltIiwiYXNzaWduZWVOYW1lIjoiI ...