几乎所有的Node.js开发人员可以告诉你`require()`函数做什么,但我们又有多少人真正知道它是如何工作的?我们每天都使用它来加载库和模块,但它的行为,对于我们来说反而是一个谜。
出于好奇,我钻研了node的核心代码来找出在引擎下发生了什么事。但这并不是一个单一的功能,我在node的模块系统的找到了 module.js。该文件包含一个令人惊讶的强大的且相对陌生的核心模块,控制每个文件的加载,编译和缓存。`require()`,它的横空出世,只 是冰山的一角。
module.js
function Module(id, parent) { this.id = id; this.exports = {}; this.parent = parent; // ...
在module.js在Node.js内部主要承担两个角色。首先,它为所有的Node.js模块提供了一个基础。每个文件是基本模块new出的一个新实 例,即使在该文件已经运行之后,仍然存在。这就是为什么我们能够性为module.exports附加属并在需要时返回它们。
该模块的第二大任务是处理node的模块加载机制。我们使用的独立操作的“require”函数实际上是一个抽象概念的 module.require,这本身就是只是一个简单的关于Module._load功能的封装。此load方法处理每个文件的实际加载,并在那里开始 我们的旅程。
Module._load
Module._load = function(request, parent, isMain) { // 1. Check Module._cache for the cached module. // 2. Create a new Module instance if cache is empty. // 3. Save it to the cache. // 4. Call module.load() with your the given filename. // This will call module.compile() after reading the file contents. // 5. If there was an error loading/parsing the file, // delete the bad module from the cache // 6. return module.exports };
Module._load负责加载新的模块和管理模块的缓存。缓存加载的每个模块减少冗余文件的读取次数,并可以显著地加快您应用程序的速度。此外,共享模块实例允许单例特性的模块,保持在项目中的状态。
如果某个模块没有在缓存中存在,Module._load将创建该文件的一个新的基本模块。然后,它会告诉模块在将它们发送到module._compile之前阅读新文件的内容。[1]
如果您注意到上面的步骤#6,你会看到module.exports已被返回给用户。这就是为什么当你在定义公共接口使用时,你使用exports 和module.exports,因为Module._load将接下来返回require的内容。我很惊讶,这里没有更多的功能,但如果有的话那更好。
module._compile
Module.prototype._compile = function(content, filename) { // 1. Create the standalone require function that calls module.require. // 2. Attach other helper methods to require. // 3. Wraps the JS code in a function that provides our require, // module, etc. variables locally to the module scope. // 4. Run that function };
这是真正的奇迹发生的地方。首先,一个特殊的独立操作的require函数是为该模块创建的。这是我们需要的并且都熟悉的功能。而函数本身只是一个在Module.require的封装,它也包含了一些便于我们使用的鲜为人知的辅助方法:
· require():加载一个外部模块
· require.resolve():解析一个模块名到它的绝对路径
· require.main:主模块
· require.cache:所有缓存好的模块
· ·require.extensions:根据其扩展名,对于每个有效的文件类型可使用的编制方法
一旦require准备好了,整个加载的源代码就会被封装在一个新的函数里,可以接受require,module,exports和所有其他暴露的变量作为参数。这是一个仅仅为封装模块的而创建的函数,以便于在防止与Node.js的环境产生冲突。
(function (exports, require, module, __filename, __dirname) { // YOUR CODE INJECTED HERE! });
该Module._compile方法是同步执行的,所以对Module._load的调用只能等到这段代码运行结束,并将module.exprts返回给用户。
结论
因此,我们已经了解了require的全部代码,并已经初步了解它是如何工作的。
如果你已经按照这一切的方式做了,那么你已经为最后的秘密做好准备:require('module')。这是正确的,该模块系统本身可以通过模块系统被加载。
相关推荐
Node.js 的安装与使用 安装 Node.js n 和 nvm nrm MongoDB 的安装与使用 安装与启动 MongoDB Robomongo 和 MongoChef Node.js 知识点讲解 require exports 和 module.exports Promise 环境变量 packge.json semver ...
在Node.js中,非对称加密是一种用于保护数据安全的重要技术。它涉及到两个密钥:公钥和私钥。公钥可以公开分享,用于加密数据,而私钥必须保密,用于解密数据。这种机制使得只有拥有私钥的接收者才能读取由公钥加密...
Node.js是一种流行的服务器端JavaScript运行环境,它允许开发者使用JavaScript语言来编写服务器端应用程序。依赖注入是一种设计模式,它允许将依赖项注入到需要它们的代码模块中,而不是由模块自己创建。这种模式有...
在node.js中,模块使用CommonJS规范,一个文件是一个模块 node.js中的模块可分为三类 内部模块 – node.js提供的模块如 fs,http,path等 自定模块 – 我们自己写的模块 第三方模块 – 通过npm安装的模块 node.js...
Express是一个轻量级的Web应用框架,极大地简化了Node.js的Web开发工作。 1. 首先,我们需要安装Express。在项目根目录下,运行以下命令: ``` npm install express ``` 2. 创建Express应用,并添加两个路由,分别...
Node.js是基于Chrome V8引擎的JavaScript运行环境,它使用事件驱动、非阻塞I/O模型,非常适合构建可扩展的网络应用。在Node.js中,http模块用于处理HTTP服务器端和客户端的逻辑。http.ServerResponse对象代表了一个...
Node.js是JavaScript的一种运行环境,使用事件驱动、非阻塞I/O模型来实现网络应用的高并发性,非常适合处理大量并发的I/O操作,因此在实现网络通讯模块方面有着自身的优势。Node.js中的网络通讯模块主要是指Net、...
windows下安装Node.js和安装普通软件毫无差别,装完后打开Node.js的快捷方式,或者直接cmd,你懂的。 创建findString.js var path = require(path); var fs = require(fs); var filePath = process.argv[2]; var ...
在IT领域,尤其是在系统管理与自动化操作中,Node.js是一个常用工具,它可以用来编写命令行应用和批处理脚本。本文将深入探讨如何利用Node.js在命令行或批处理环境中更改Linux用户的密码。 首先,我们要了解Linux...
总结来说,Node.js和浏览器环境在JavaScript的执行上下文中有着本质的不同,这些差异决定了它们在各自领域的应用和开发方式。了解这些差异对于编写适应不同环境的JavaScript代码至关重要。无论是Node.js的服务器端...
Node.js实现Websocket的数据接收与发送是Web开发中的一个重要技术点。Websocket是一种在单个TCP连接上进行全双工通信的协议,它允许服务器主动向客户端推送信息。Node.js凭借其非阻塞、事件驱动的特性,非常适合处理...
CommonJS 是 Node.js 环境下广泛采用的模块化规范,通过 `require` 函数来导入模块,通过 `module.exports` 或 `exports` 来导出模块。在浏览器环境中,由于原生不支持 CommonJS,webpack 通过 Babel 等转换工具,将...
在本文中,我们将深入探讨如何在Node.js环境中使用Express框架连接到MySQL数据库。这是一个常见的任务,对于构建Web应用程序至关重要,特别是在Ubuntu系统上。首先,让我们从安装MySQL开始。 1. **安装MySQL**: ...