Das Modulsystem in Node.js verstehen
Verwandte Empfehlungen: „node js-Tutorial“
Module von Node.js
JavaScript wurde als einfache Skriptsprache zum Hinzufügen interaktiver Funktionen zu Webseiten herausgebracht. Zu Beginn enthielt es kein Modulsystem Das Schreiben des gesamten Codes in einer Datei und die Verwendung von Funktionen zur Unterscheidung von Funktionseinheiten können die Entwicklung komplexer Anwendungen nicht mehr unterstützen einfacher für Entwickler, Code zu organisieren.
import _ from 'lodash'; class Fun {} export default Fun;
Die obigen drei Codezeilen zeigen die beiden wichtigsten Elemente eines Modulsystems, Import und Export.
export
wird verwendet, um die externe Schnittstelle von festzulegen Das Modulexport
用于规定模块的对外接口import
用于输入其他模块提供的功能
而在 ES6 之前,社区出现了很多模块加载方案,最主要的有 CommonJS 和 AMD 两种,Node.js 诞生早于 ES6,模块系统使用的是类似 CommonJS 的实现,遵从几个原则
一个文件是一个模块,文件内的变量作用域都在模块内
使用
module.exports
对象导出模块对外接口使用
require
引入其它模块
circle.js
const { PI } = Math; module.exports = function area(r) { PI * r ** 2; };
上面代码就实现了 Node.js 的一个模块,模块没有依赖其它模块,导出了方法 area
计算圆的面积
test.js
const area = require('./circle.js'); console.log(`半径为 4 的圆的面积是 ${area(4)}`);
模块依赖了 circle.js,使用其对外暴露的 area 方法,计算圆的面积
module.exports
模块对外暴露接口使用 module.exports,常见的有两种用法:为其添加属性或赋值到新对象test.js
// 添加属性 module.exports.prop1 = xxx; module.exports.funA = xxx; module.exports.funB = xxx; // 赋值到全新对象 module.exports = { prop1, funA, funB, };
两种写法是等价的,使用时候没区别
const mod = require('./test.js'); console.log(mod.prop1); console.log(mod.funA());
还有另外一种直接使用 exports
对象的方法,但是只能对其添加属性,不能赋值到新对象,后面会介绍原因
// 正确的写法:添加属性 exports.prop1 = xxx; exports.funA = xxx; exports.funB = xxx; // 赋值到全新对象 module.exports = { prop1, funA, funB, };
require('id')
模块类型
require 用法比较简单,id 支持模块名和文件路径两种类型
模块名
const fs = require('fs'); const _ = require('lodash');
示例中的 fs、lodash 都是模块名,fs 是 Node.js 内置的核心模块,lodash 是通过 npm 安装到 node_modules
下的第三方模块,如果出现重名,优先使用系统内置模块
因为一个项目内可能会包含多个 node_modules 文件夹(Node.js 比较失败的设计),第三方模块查找过程会遵循就近原则逐层上溯(可以在程序中打印 module.paths
查看具体查找路径),直到根据 NODE_PATH
环境变量查找到文件系统根目录,具体过程可以参考官方文档
此外,Node.js 还会搜索以下的全局目录列表:
- $HOME/.node_modules
- $HOME/.node_libraries
- $PREFIX/lib/node
其中 $HOME
是用户的主目录, $PREFIX
是 Node.js 里配置的 node_prefix
。强烈建议将所有的依赖放在本地的 node_modules 目录,这样将会更快地加载,且更可靠
文件路径
模块还可以可以使用文件路径加载,这是项目内自定义模块的通用加载方式,路径可以省略拓展名,会按照 .js、.json、.node 顺序尝试
- 以
'/'
为前缀的模块是文件的绝对路径,按照系统路径查找模块 - 以
'./'
为前缀的模块是相对于当前调用 require 方法的文件,不受后续模块在哪里被使用到影响
单次加载 & 循环依赖
模块在第一次加载后会被缓存到 Module._cache
,如果每次调用 require('foo')
都解析到同一文件,则返回相同的对象,同时多次调用 require(foo)
不会导致模块的代码被执行多次。 Node.js 根据实际的文件名缓存模块,因此从不同层级目录引用相同模块不会重复加载。
理解的模块单次加载机制方便我们理解模块循环依赖后的现象a.js
console.log('a 开始'); exports.done = false; const b = require('./b.js'); console.log('在 a 中,b.done = %j', b.done); exports.done = true; console.log('a 结束');
b.js
console.log('b 开始'); exports.done = false; const a = require('./a.js'); console.log('在 b 中,a.done = %j', a.done); exports.done = true; console.log('b 结束');
main.js
import
wird zum Importieren von Funktionen verwendet, die von anderen Modulen bereitgestellt werden
Vor ES6 erschienen in der Community viele Lösungen zum Laden von Modulen, am häufigsten Wichtige davon waren CommonJS und AMD, und Node.js wurde geboren. Vor ES6 verwendete das Modulsystem eine Implementierung ähnlich wie CommonJS und folgte mehreren Prinzipien. Eine Datei ist ein Modul, und der Umfang der Variablen in der Datei ist es innerhalb des Moduls
Verwenden Siemodule .exports
Die externe Schnittstelle des Objektexportmoduls🎜Verwenden Sie require
, um andere Module einzuführen🎜 🎜circle.js
🎜console.log('main 开始'); const a = require('./a.js'); const b = require('./b.js'); console.log('在 main 中,a.done=%j,b.done=%j', a.done, b.done);
area zur Berechnung der Fläche eines Kreises🎜🎜<code>test.js
🎜main 开始 a 开始 b 开始 在 b 中,a.done = false b 结束 在 a 中,b.done = true a 结束 在 main 中,a.done=true,b.done=true
module.exports🎜🎜Die extern verfügbar gemachte Schnittstelle des Moduls verwendet module.exports. Es gibt zwei häufige Verwendungszwecke: Hinzufügen von Attributen oder Zuweisen von Werten zu neuen Objekten🎜test.js🎜<div class="code" style="position:relative; padding:0px; margin:0px;"><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">(function(exports, require, module, __filename, __dirname) {
// 模块的代码实际上在这里
});</pre><div class="contentsignin">Nach dem Login kopieren</div></div><div class="contentsignin">Nach dem Login kopieren</div></div>🎜Die beiden Schreibmethoden sind gleichwertig und es gibt keinen Unterschied bei ihrer Verwendung🎜<div class="code" style="position:relative; padding:0px; margin:0px;"><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">const exports = module.exports;
(function(exports, require, module, __filename, __dirname) {
// 模块的代码实际上在这里
});</pre><div class="contentsignin">Nach dem Login kopieren</div></div><div class="contentsignin">Nach dem Login kopieren</div></div>🎜Es gibt eine andere Möglichkeit, die Objektmethode <code>exports direkt zu verwenden, aber Sie können ihr nur Attribute hinzufügen und Es kann nicht einem neuen Objekt zugewiesen werden. Der Grund wird später erläutert relativ einfach, id unterstützt zwei Typen: Modulname und Dateipfad🎜<h4 id="Module-name">Module name</h4>
<div class="code" style="position:relative; padding:0px; margin:0px;"><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">{
"presets": [
["@babel/preset-env", {
"targets": {
"node": "8.9.0",
"esmodules": true
}
}]
]
}</pre><div class="contentsignin">Nach dem Login kopieren</div></div><div class="contentsignin">Nach dem Login kopieren</div></div>🎜fs und lodash im Beispiel sind beide Modulnamen, fs ist das integrierte Kernmodul Von Node.js ist lodash ein Modul eines Drittanbieters, das über npm unter <code>node_modules
installiert wird. Wenn ein doppelter Name vorhanden ist, geben Sie der Verwendung des im System integrierten Moduls Vorrang, da ein Projekt möglicherweise With enthält Wenn Sie mehrere node_modules-Ordner verwenden (ein relativ fehlgeschlagenes Design von Node.js), folgt der Modulsuchprozess von Drittanbietern dem Prinzip der Nähe und geht Schicht für Schicht nach oben (Sie können module.paths
im Programm drucken). um den spezifischen Suchpfad anzuzeigen) bis Finden Sie das Dateisystem-Stammverzeichnis gemäß der Umgebungsvariablen NODE_PATH
Den spezifischen Vorgang finden Sie in der offiziellen Dokumentation🎜🎜Darüber hinaus führt Node.js auch eine Suche durch die folgende globale Verzeichnisliste:🎜🎜$HOME/.node_modules 🎜$HOME/.node_libraries🎜$PREFIX/lib/node
🎜wo $HOME
ist das Home-Verzeichnis des Benutzers, $ PREFIX
ist das in Node.js konfigurierte node_prefix
. Es wird dringend empfohlen, alle Abhängigkeiten im lokalen Verzeichnis node_modules zu platzieren, da dies schneller und zuverlässiger ist. 🎜Dateipfad
🎜Module können auch über Dateipfade geladen werden Eine übliche Lademethode für benutzerdefinierte Module im Projekt. Die Pfaderweiterung kann weggelassen werden, und Module mit dem Präfix '/'
werden in der Reihenfolge .js, .json und .node🎜 ausprobiert ul>🎜 Ist der absolute Pfad der Datei, suchen Sie nach Modulen entsprechend dem Systempfad🎜Module mit dem Präfix './'
beziehen sich auf die Datei, die aktuell die erforderliche Methode aufruft, und sind davon nicht betroffen, wo nachfolgende Module verwendet werdenEinzelladung und zirkuläre Abhängigkeit
🎜Das Modul wird in Modul nach dem ersten Laden von ._cache
: Wenn jeder Aufruf von require('foo')
in dieselbe Datei aufgelöst wird, wird dasselbe Objekt zurückgegeben und require(foo )
wird mehrmals aufgerufen. > Führt nicht dazu, dass der Code des Moduls mehrmals ausgeführt wird. Node.js speichert Module basierend auf ihren tatsächlichen Dateinamen zwischen, sodass dasselbe Modul nicht zweimal geladen wird, wenn es von verschiedenen Verzeichnisebenen aus referenziert wird. 🎜🎜Der gut verstandene Modul-Einzellademechanismus erleichtert uns das Verständnis des Phänomens der zirkulären Modulabhängigkeiten🎜a.js
🎜rrreee🎜b.js
🎜rrreee🎜 main.js
:🎜rrreee🎜Wenn main.js a.js lädt, lädt a.js b.js. Zu diesem Zeitpunkt versucht b.js, a.js zu laden🎜🎜Um Endlosschleifen zu verhindern , es wird eine 🎜unvollendete Kopie🎜 des Exportobjekts von a.js an das b.js-Modul übergeben, dann schließt b.js den Ladevorgang ab und stellt das Exportobjekt dem a.js-Modul zur Verfügung 🎜🎜, sodass die Ausgabe des Beispiel ist 🎜main 开始
a 开始
b 开始
在 b 中,a.done = false
b 结束
在 a 中,b.done = true
a 结束
在 main 中,a.done=true,b.done=true
Nach dem Login kopierenNach dem Login kopieren
main 开始 a 开始 b 开始 在 b 中,a.done = false b 结束 在 a 中,b.done = true a 结束 在 main 中,a.done=true,b.done=true
看不懂上面的过程也没关系,日常工作根本用不到,即使看懂了也不要在项目中使用循环依赖!
工作原理
Node.js 每个文件都是一个模块,模块内的变量都是局部变量,不会污染全局变量,在执行模块代码之前,Node.js 会使用一个如下的函数封装器将模块封装
(function(exports, require, module, __filename, __dirname) { // 模块的代码实际上在这里 });
- __filename:当前模块文件的绝对路径
- __dirname:当前模块文件据所在目录的绝对路径
- module:当前的模块实例
- require:加载其它模块的方法,module.require 的快捷方式
- exports:导出模块接口的对象,module.exports 的快捷方式
回头看看最开始的问题,为什么 exports 对象不支持赋值为其它对象?把上面函数添加一句 exports 对象来源就很简单了
const exports = module.exports; (function(exports, require, module, __filename, __dirname) { // 模块的代码实际上在这里 });
其它模块 require 到的肯定是模块的 module.exports 对象,如果吧 exports 对象赋值给其它对象,就和 module.exports 对象断开了连接,自然就没用了
在 Node.js 中使用 ES Module
随着 ES6 使用越来越广泛,Node.js 也支持了 ES6 Module,有几种方法
babel 构建
使用 babel 构建是在 v12 之前版本最简单、通用的方式,具体配置参考 @babel/preset-env(https://babeljs.io/docs/en/babel-preset-env)
.babelrc
{ "presets": [ ["@babel/preset-env", { "targets": { "node": "8.9.0", "esmodules": true } }] ] }
原生支持
在 v12 后可以使用原生方式支持 ES Module
开启
--experimental-modules
模块名修改为
.mjs
(强烈不推荐使用)或者 package.json 中设置"type": module
这样 Node.js 会把 js 文件都当做 ES Module 来处理,更多详情参考官方文档(https://nodejs.org/dist/latest-v13.x/docs/api/esm.html)
更多编程相关知识,请访问:编程视频!!
Das obige ist der detaillierte Inhalt vonDas Modulsystem in Node.js verstehen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Heiße KI -Werkzeuge

Undresser.AI Undress
KI-gestützte App zum Erstellen realistischer Aktfotos

AI Clothes Remover
Online-KI-Tool zum Entfernen von Kleidung aus Fotos.

Undress AI Tool
Ausziehbilder kostenlos

Clothoff.io
KI-Kleiderentferner

Video Face Swap
Tauschen Sie Gesichter in jedem Video mühelos mit unserem völlig kostenlosen KI-Gesichtstausch-Tool aus!

Heißer Artikel

Heiße Werkzeuge

Notepad++7.3.1
Einfach zu bedienender und kostenloser Code-Editor

SublimeText3 chinesische Version
Chinesische Version, sehr einfach zu bedienen

Senden Sie Studio 13.0.1
Leistungsstarke integrierte PHP-Entwicklungsumgebung

Dreamweaver CS6
Visuelle Webentwicklungstools

SublimeText3 Mac-Version
Codebearbeitungssoftware auf Gottesniveau (SublimeText3)

Heiße Themen

Dieser Artikel vermittelt Ihnen ein detailliertes Verständnis des Speichers und Garbage Collectors (GC) der NodeJS V8-Engine. Ich hoffe, er wird Ihnen hilfreich sein!

Der nicht blockierende und ereignisgesteuerte Knotendienst hat den Vorteil eines geringen Speicherverbrauchs und eignet sich sehr gut für die Verarbeitung massiver Netzwerkanforderungen. Unter der Voraussetzung massiver Anfragen müssen Probleme im Zusammenhang mit der „Speicherkontrolle“ berücksichtigt werden. 1. Der Garbage-Collection-Mechanismus und die Speicherbeschränkungen von V8 Js wird von der Garbage-Collection-Maschine gesteuert

Die Auswahl eines Docker-Images für Node mag trivial erscheinen, aber die Größe und potenziellen Schwachstellen des Images können erhebliche Auswirkungen auf Ihren CI/CD-Prozess und Ihre Sicherheit haben. Wie wählen wir also das beste Node.js-Docker-Image aus?

Das Dateimodul ist eine Kapselung der zugrunde liegenden Dateioperationen, wie z. B. Lesen/Schreiben/Öffnen/Schließen/Löschen von Dateien, Hinzufügen usw. Das größte Merkmal des Dateimoduls besteht darin, dass alle Methoden zwei Versionen von **synchronem** und **bereitstellen. asynchron**, mit Methoden mit dem Suffix sync sind alle Synchronisationsmethoden, und diejenigen ohne sind alle heterogene Methoden.

Node 19 wurde offiziell veröffentlicht. Dieser Artikel wird Ihnen eine detaillierte Erklärung der 6 Hauptfunktionen von Node.js 19 geben. Ich hoffe, er wird Ihnen hilfreich sein!

Wie führt Node.js GC (Garbage Collection) durch? Der folgende Artikel führt Sie durch.

Die Ereignisschleife ist ein grundlegender Bestandteil von Node.js und ermöglicht die asynchrone Programmierung, indem sie sicherstellt, dass der Hauptthread nicht blockiert wird. Das Verständnis der Ereignisschleife ist für die Erstellung effizienter Anwendungen von entscheidender Bedeutung. Der folgende Artikel wird Ihnen ein detailliertes Verständnis der Ereignisschleife in Node vermitteln. Ich hoffe, er wird Ihnen hilfreich sein!

Wie packe ich die ausführbare Datei von nodejs mit pkg? Im folgenden Artikel erfahren Sie, wie Sie mit pkg ein Node-Projekt in eine ausführbare Datei packen. Ich hoffe, dass er Ihnen weiterhilft!
