require() 方法详解
在 NodeJS 中有一个方法是我们使用频率最高的,那就是 require 方法。NodeJs 遵循 CommonJS 规范,该规范的核心是通过 require 来加载其他依赖的模块。
几个问题
module.exports 或者 exports 是全局变量吗?
模块的加载是同步还是异步?
循环引用会不会产生性能问题或者导致错误?
什么是 CommonJS
每一个文件就是一个模块,拥有自己独立的作用域,变量,以及方法等,对其他的模块都不可见。CommonJS 规范规定,每个模块内部,module 变量代表当前模块。这个变量是一个对象,它的 exports 属性(即module.exports
)是对外的接口。
Node 模块的分类
build-in modules —— Nodejs 中以 C++ 形式提供的模块。
constant module —— Nodejs 中定义常量的模块。
native module —— Nodejs 中以 javascript 形式提供的模块。
第三方 module —— 由第三方提供的模块。
module 对象
NodeJs 内部提供一个 Module 构建函数。所有模块都是 Module 的实例。
每个模块内部,都有一个 module 对象,代表当前模块。它有以下属性。
module 对象的属性
module.id
模块的识别符,通常是带有绝对路径的模块文件名。module.filename
模块的文件名,带有绝对路径。module.loaded
返回一个布尔值,表示模块是否已经完成加载。module.parent
返回一个对象,表示调用该模块的模块(程序入口文件的 module.parent 为 null)module.children
返回一个数组,表示该模块要用到的其他模块。module.exports
表示模块对外输出的值。module.exports 属性
module.exports
属性表示当前模块对外输出的接口,其他文件加载该模块,实际上就是读取module.exports
变量。module.exports
属性表示当前模块对外输出的接口,其他文件加载该模块,实际上就是读取module.exports
变量。exports 变量
我们有时候会这么写:
这样也可以拿到正确的结果,这是因为:exports 变量指向 module.exports。这等同在每个模块头部,有一行这样的命令。
注意:不能直接给 exports 变量赋值,这样会改变 exports 的指向,不再指向 module.exports。在其他模块使用 require 方法是拿不到赋给 exports 的值的,因为 require 方法获取的是其他模块的 module.exports 的值。
建议:尽可能的使用 module.exports
来导出结果。
模块的流程
创建模块
导出模块
加载模块
使用模块
require 方法
require 是 node 用来加载并执行其它文件导出的模块的方法。
在 NodeJs 中,我们引入的任何一个模块都对应一个 Module 实例,包括入口文件。
完整步骤:
调用父模块的 require 方法(父模块是指调用模块的当前模块)
调用 Module 的 _load 方法
通过
Module._resolveFilename
获取模块的路径 fileName
根据 fileName 判断是否存在该模块的缓存
如果存在缓存,则调用
updateChildren
方法在更新缓存内容,并返回缓存如果不存在缓存,则继续执行
当做原生模块,调用
loadNativeModule
方法进行加载如果加载成功,则返回该原生模块
否则,继续执行
根据当前模块名(路径)和父模块对象生成一个 Module 实例:
再判断该模块是否是入口文件
将该模块的实例存入到 Module 的缓存中
该模块的实例调用自身的
load
方法,根据 fileName 加载模块
获取该模块文件的后缀名称
如果后缀名称是 ES Module 格式的(.mjs),则判断 Module 是否支持.mjs 文件的解析,如果不支持,则抛出异常。
根据后缀名称解析模块文件内容
根据 fileName 读取文件内容
编译并执行读取到的文件,调用 module 自身的
_complile
方法:
_compile
主要内容步骤:
wrapSafe
方法的返回值
具体获得上图结果的代码是:
修改该模块的加载状态为 true
加载成功。
总结
通过上面的调试过程可得出以下结论:
在 NodeJs 中,从入口文件开始,一切皆 Module。
模块的加载是同步的。
由于缓存机制的存在,模块的循环引用对性能的影响微乎其微,并且循环引用到的模块可能是不完整的,并且可能会导致错
require 查找模块的流程如下:
文件路径的解析流程图如下:
~本文完~
学习有趣的知识,结识有趣的朋友,塑造有趣的灵魂!
大家好!我是〖编程三昧〗的作者 隐逸王,我的公众号是『编程三昧』,欢迎关注,希望大家多多指教!
知识与技能并重,内力和外功兼修,理论和实践两手都要抓、两手都要硬!
版权声明: 本文为 InfoQ 作者【编程三昧】的原创文章。
原文链接:【http://xie.infoq.cn/article/0a4c7286e06fc352db0388b34】。
本文遵守【CC BY-NC-ND】协议,转载请保留原文出处及本版权声明。
评论