介绍
Node.js 中的一个重要概念是您想知道依赖管理的处理方式。这种依赖管理是 Node.js 核心体验的一部分。在这篇文章中,我们将学习依赖管理的各种模式以及 Nodejs 如何加载依赖。
因此,我们可以为所有内容使用单个js 文件编写我们的应用程序,但这不是模块化的。Node.js 使编写模块化代码变得非常简单。
在我们深入研究细节之前,首先要回答的问题是模块。它是什么?我们为什么要关心它?
简单来说,一个模块就是一段代码,我们将它们组合在一起,以便共享和重用。因此,模块允许我们将应用程序中的复杂性分解为小块。这有助于理解代码直至查找和修复错误。如果你想了解更多关于 JavaScript 模块系统的信息,你可以查看这篇 文章。
Node 使用一种工具来要求 某些行为。这是基于 CommonJS 的。简而言之,为了引入 JavaScript 文件,我们使用关键字require。
我假设您已经了解 Nodejs 的一些基础知识。如果您是 Nodejs 新手,您还可以查看我之前的文章Node.js – Introduction了解一些背景信息。
设置应用程序
让我们从简单的开始。我为项目创建了一个目录,使用npm init 对其进行初始化,并创建了两个 JavaScript 文件(app.js 和 appMsg.js)。这就是投影的样子,我们将以此作为演示的起点。此外,您可以从文章后面提到的 git repo 链接下载最终代码。
此时,两个 .js 文件都是空的。让我们用以下更改更新appMsgs.js文件:
我们可以看到module.exports关键字的使用。此语法用于公开给定文件 (appMsgs.js) 中的属性或对象,然后可以在另一个文件中使用这些属性或对象,在我们的示例中为app.js。
在这个系统中,每个文件都可以访问称为module.exports. 因此,我们在 appMsgs.js 文件中公开了一些项目,现在让我们看看app.js如何使用(需要)这些属性:
现在要引用文件,我们使用require关键字。当我们 时require,它将返回一个将表示该模块化代码的对象,因此我们将其分配给一个变量appMsgs变量,然后在console.log语句中简单地使用属性。当我们执行代码时,我们可以看到以下输出:
所以,这 require是在执行 JavaScript,允许它构造一个返回给我们的具有一些功能的对象。
这可能是一个类构造函数或一个对象,其中包含许多元素或一些简单的属性。这有不同的模式,我们可以导出不止一件东西,甚至导出复杂的对象。
因此,通过管理require和module.exports,我们可以创建这些模块化应用程序。
所需的功能加载代码并加载一次。因此,无论在这里执行什么代码,都不会第二次执行。因此,如果其他人通过 请求此对象require,它将获得此对象的缓存版本。让我们看看其他一些方法。
我已经更改了代码,现在不是公开对象,而是导出function. 每次作为函数调用时都会执行此代码。
接下来我们看看它在app.js文件中是如何使用的:
我们可以像执行函数一样执行它,而不是调用属性。所以,这里的区别在于,每次我们执行这段代码时,都会重新执行函数内部的代码。
这是我们运行代码时的输出:
所以,我们已经看到了两种模式module.exports 和它们的区别。另一个常见的模式,你会想知道使用 this 作为构造函数 方法。让我们看一个例子:
这是更新后的app.js文件:
因此,这与在 JavaScript 中创建伪类 并允许创建它的实例 时本质上是相同的。
这是此更改的输出:
现在,让我们看看这些模式的另一个例子:
我创建了一个名为userRepo.js的新文件,如下所示:
这是此更改的app.js和执行结果:
对单个文件使用require并不少见,但您还应该注意另一种模式。接下来让我们看看文件夹的依赖关系。
文件夹依赖
我们将退后一步,了解 Nodejs 如何查找依赖项。记住前面例子中的那句话:
JavaScript:
var appMsgs = require ( "./appMsgs" )
Node 仍然会寻找appMsgs.js文件,但它也会寻找appMsgs 作为目录 ,无论先找到哪个,它都会将其拉入。
现在让我们看看代码:
我创建了一个文件夹, 名为记录器 和文件夹内,我创建了一个文件index.js。
这是index.js文件中的代码:
这是需要此模块的 app.js文件:
所以,在我们的例子中,我们可以说:
JavaScript:
var logger = require ( "./logger/index.js" )
这将是完全有效的。但相反,只需说以下内容:
JavaScript:
var logger = require ( "./logger" )
由于没有logger.js,有一个 logger directory,默认情况下它会加载index.js作为我们记录器的起点。这就是我给index.js命名的原因,让我们看看执行这段代码的结果是什么:
因此,就其本身而言,您可能会想,为什么要费心进行创建文件夹和 inex.js 的额外步骤?
原因是您可能将一个复杂的依赖放在一起,而这个依赖可能有它所依赖的其他部分。需要记录器的调用者不需要知道有一堆这些其他依赖项。
这是一种封装形式,因此当我们构建更复杂的部分时,我们可以从多个文件中构建它们。然后在消费者端,使用单个文件。它只是暗示文件夹是管理这些依赖项的好方法。
节点包管理器 (NPM)
我们还想简要讨论的另一件事是 NPM。您可能已经知道它的用途。这带来了额外的功能,它的使用非常简单。
我们可以使用npm安装依赖项:
npm install underscore;
然后可以简单地在app.js 中使用它,如下所示:
可以看到我们如何使用下划线包提供的功能。此外,当我们需要这个模块时,我们没有指定文件路径,我们只是使用它的名称,Nodejs 将从您应用程序的node_modules文件夹中加载这个模块。
这是执行的输出:
概括
在这篇文章中,我们学习了 Nodejs 如何管理其依赖项,并且我们看到了在我们的应用程序中使用的一些模式。您可以从此Git 存储库下载源代码。