Heim  >  Artikel  >  Web-Frontend  >  Detaillierte Erläuterung des Ladens des Node.js-Moduls

Detaillierte Erläuterung des Ladens des Node.js-Moduls

高洛峰
高洛峰Original
2016-12-26 09:32:441432Durchsuche

JavaScript ist eine der am häufigsten verwendeten Programmiersprachen der Welt. Es ist die universelle Sprache der Webwelt und wird von allen Browsern verwendet. Die Geburt von JavaScript lässt sich bis in die Netscape-Ära zurückverfolgen. Sein Kerninhalt wurde hastig entwickelt, um mit Microsoft zu konkurrieren und am damaligen heftigen Browserkrieg teilzunehmen. Aufgrund der vorzeitigen Veröffentlichung führte es zwangsläufig zu einigen nicht so guten Funktionen.

Trotz seiner kurzen Entwicklungszeit verfügt JavaScript immer noch über viele leistungsstarke Funktionen, außer dass jedes Skript einen globalen Namensraum teilt.

Sobald eine Webseite JavaScript-Code lädt, wird dieser in den globalen Namespace eingefügt und teilt sich den gleichen Adressraum mit allen anderen geladenen Skripten. Dies führt zu vielen Sicherheitsproblemen, Konflikten und einigen häufigen Problemen. Dies macht es schwierig, Fehler aufzuspüren und zu beheben.

Aber zum Glück hat Node einige Spezifikationen für serverseitiges JavaScript festgelegt und auch den CommonJS-Modulstandard implementiert. In diesem Standard hat jedes Modul seinen eigenen Kontext und unterscheidet sich von anderen Modulen. Dies bedeutet, dass Module den globalen Bereich nicht verschmutzen, da es keinen globalen Bereich gibt und Module sich nicht gegenseitig stören.

In diesem Kapitel lernen wir verschiedene Module kennen und erfahren, wie man sie lädt.

Die Aufteilung Ihres Codes in eine Reihe klar definierter Module kann Ihnen helfen, die Kontrolle über Ihre Anwendung zu übernehmen. Im Folgenden erfahren Sie, wie Sie Ihre eigenen Module erstellen und verwenden.

Verstehen Sie, wie Node Module lädt

In Node können Sie Module über Dateipfade oder Modulnamen referenzieren. Wenn Sie ein Nicht-Kernmodul namentlich referenzieren, verweist Node schließlich auf den Modulnamen . zum entsprechenden Moduldateipfad. Die Kernmodule, die Kernfunktionen enthalten, werden beim Start von Node vorinstalliert.

Zu den Nicht-Kernmodulen gehören Module von Drittanbietern, die mit NPM (Node Package Manager) installiert wurden, sowie lokale Module, die von Ihnen oder Ihren Kollegen erstellt wurden.

Jedes vom aktuellen Skript importierte Modul stellt Programmierern eine Reihe öffentlicher APIs zur Verfügung. Bevor Sie das Modul verwenden, müssen Sie es mit der Funktion „require“ importieren, etwa so:

var module = require(‘module_name')

Oben: Der Code importiert ein Modul mit dem Namen module_name, bei dem es sich um ein Kernmodul oder ein mit NPM installiertes Modul handeln kann. Die Funktion require gibt ein Objekt zurück, das alle öffentlichen APIs des Moduls enthält. Abhängig vom Modul kann das zurückgegebene Objekt ein beliebiger JavaScript-Wert, eine Funktion oder ein Objekt sein, das eine Reihe von Eigenschaften enthält (eine Funktion, ein Array oder ein beliebiges JavaScript-Objekt).

Modul exportieren

Das CommonJS-Modulsystem ist die einzige Möglichkeit, Objekte und Funktionen zwischen Dateien unter Node zu teilen. Bei einem sehr komplexen Programm sollten Sie einige Klassen, Objekte oder Funktionen in eine Reihe klar definierter wiederverwendbarer Module umstrukturieren. Dem Benutzer des Moduls stellt das Modul nur den von Ihnen angegebenen Code zur Verfügung.

Im folgenden Beispiel erfahren Sie, dass es eine Eins-zu-eins-Entsprechung zwischen Dateien und Modulen in Node gibt. Wir haben eine Datei namens „circle.js“ erstellt, die nur den Circle-Konstruktor exportiert.

function Circle(x, y, r) {
       function r_squared() {
              return Math.pow(r, 2);
       }
       function area() {
              return Math.PI * r_squared();
       }
       return {area: area};
}
module.exports = Circle;

Die wichtigste Zeile im Code ist die letzte Zeile, die definiert, was das Modul exportiert. module ist eine spezielle Variable, die das aktuelle Modul selbst darstellt, und module.exports ist das vom Modul exportierte Objekt. In diesem Beispiel haben wir den Konstruktor von Circle exportiert, damit Modulbenutzer dieses Modul erstellen können Kreisinstanzen.

Sie können auch einige komplexe Objekte exportieren. module.exports wird als leeres Objekt initialisiert. Sie können jeden Inhalt, den Sie der Außenwelt zugänglich machen möchten, als Attribute des module.exports-Objekts exportieren. Sie entwerfen beispielsweise ein Modul, das eine Reihe von Funktionen verfügbar macht:

                  function printA() {
         console.log('A');
}
function printB() {
         console.log('B');
}
function printC() {
         console.log('C');
}
module.exports.printA = printA;
module.exports.printB = printB;
module.exports.pi = Math.PI;

Dieses Modul exportiert zwei Funktionen (printA und printB) und eine Zahl (pi). Der aufrufende Code sieht folgendermaßen aus:

var myModule2 = require('./myModule2');
myModule2.printA(); // -> A
myModule2.printB(); // -> B
console.log(myModule2.pi); // -> 3.141592653589793

Laden von Modulen

Wie bereits erwähnt, können Sie die Funktion „require“ zum Laden von Modulen verwenden. Sie müssen sich keine Sorgen machen, dass der Aufruf von „require“ im Code Auswirkungen auf den globalen Namespace hat, da dieser vorhanden ist So etwas gibt es in Node nicht. Das Konzept des globalen Namespace. Wenn das Modul vorhanden ist und keine Syntax- oder Initialisierungsfehler vorliegen, gibt die Anforderungsfunktion das Modulobjekt zurück und Sie können dieses Objekt einer beliebigen lokalen Variablen zuweisen.

Es gibt verschiedene Arten von Modulen, die grob in Kernmodule, lokale Module und über NPM installierte Drittanbietermodule unterteilt werden können. Je nach Modultyp gibt es mehrere Möglichkeiten, auf das Modul zu verweisen. Werfen wir einen Blick darauf und laden Sie dieses Wissen herunter.

Laden von Kernmodulen

Knoten verfügt über einige Module, die in Binärdateien, sogenannten Kernmodulen, kompiliert sind. Sie können nicht über Pfade, sondern nur über Modulnamen referenziert werden. Das Kernmodul hat die höchste Ladepriorität. Auch wenn ein Drittanbietermodul mit demselben Namen vorhanden ist, wird das Kernmodul zuerst geladen.

Wenn Sie beispielsweise das http-Kernmodul laden und verwenden möchten, können Sie Folgendes tun:

         var http = require('http');

Dadurch wird ein http-Modulobjekt zurückgegeben, das das in definierte http-Modul enthält die Node-API-Dokumentation für diese HTTP-Module.

Modul aus Datei laden

Sie können auch einen absoluten Pfad verwenden, um das Modul aus dem Dateisystem zu laden:

var myModule = require('/home/pedro/my_modules/my_module');

Sie können auch einen relativen Pfad basierend auf verwenden die aktuelle Datei:

var myModule = require('../my_modules/my_module');

var myModule2 = require('./lib/my_module_2');

注意上面的代码,你可以省略文件名的扩展名,如果Node找不到这个文件,会尝试在文件名后加上js后缀再次查找(译者注:其实除了js,还会查找json和node,具体可以看官网文档),因此,如果在当前目录下存在一个叫my_module.js的文件,会有下面两种加载方式:

var myModule = require('./my_module');
var myModule = require('./my_module.js');

加载目录模块

你还可以使用目录的路径来加载模块:

var myModule = require('./myModuleDir');

Node会假定这个目录是个模块包,并尝试在这个目录下搜索包定义文件package.json。

如果没找到,Node会假设包的入口点是index.js文件(译者注:除了index.js还会查找index.node,.node文件是Node的二进制扩展包,具体见官方文档),以上面代码为例,Node会尝试查找./myModuleDir/index.js文件。

反之,如果找到了package.json文件,Node会尝试解析它,并查找包定义里的main属性,然后把main属性的值当作入口点的相对路径。以本例来说,如果package.json定义如下:

                   {
                            "name" : "myModule",
                            "main" : "./lib/myModule.js"
                   }

Node就会尝试加载./myModuleDir/lib/myModule.js文件

从node_modules目录加载

如果require函数的参数不是相对路径,也不是核心模块名,Node会在当前目录的node_modules子目录下查找,比如下面的代码,Node会尝试查找文件./node_modules/myModule.js:

var myModule = require('myModule.js');

如果没找到,Node会继续在上级目录的node_modules文件夹下查找,如果还没找到就继续向上层目录查找,直到找到对应的模块或者到达根目录。


你可以使用这个特性来管理node_modules目录的内容或模块,不过最好还是把模块的管理任务交给NPM(见第一章),本地node_modules目录是NPM安装模块的默认位置,这个设计把Node和NPM关联在了一起。通常,作为开发人员不必太关心这个特性,你可以简单的使用NPM安装,更新和删除包,它会帮你维护node_modules目录

缓存模块

模块在第一次成功加载后会被缓存起来,就是说,如果模块名被解析到同一个文件路径,那么每次调用require(‘myModule')都确切地会返回同一个模块。

比如,有一个叫my_module.js的模块,包含下面的内容:

console.log('module my_module initializing...');
module.exports = function() {
         console.log('Hi!');
};
console.log('my_module initialized.');

然后用下面的代码加载这个模块:

var myModuleInstance1 = require('./my_module');

它会产生下面的输出:

module my_module initializing...
my_module initialized

如果我们两次导入它:

var myModuleInstance1 = require('./my_module');
var myModuleInstance2 = require('./my_module');

如果我们两次导入它:

var myModuleInstance1 = require('./my_module');
var myModuleInstance2 = require('./my_module');

输出依然是:

module my_module initializing...
my_module initialized

也就是说,模块的初始化代码仅执行了一次。当你构建自己的模块时,如果模块的初始化代码里含有可能产生副作用的代码,一定要特别注意这个特性。

小结

Node取消了JavaScript的默认全局作用域,转而采用CommonJS模块系统,这样你可以更好的组织你的代码,也因此避免了很多安全问题和bug。可以使用require函数来加载核心模块,第三方模块,或从文件及目录加载你自己的模块

还可以用相对路径或者绝对路径来加载非核心模块,如果把模块放到了node_modules目录下或者对于用NPM安装的模块,你还可以直接使用模块名来加载。

 译者注:

建议读者把官方文档的模块章节阅读一遍,个人感觉比作者讲得更清晰明了,而且还附加了一个非常具有代表性的例子,对理解Node模块加载会很有很大帮助。下面把那个例子也引用过来:

用require(X) 加载路径Y下的模块
1. 如果X是核心模块,
   a. 加载并返回核心模块
   b. 结束
2. 如果X以 './' or '/' or '../ 开始'
   a. LOAD_AS_FILE(Y + X)
   b. LOAD_AS_DIRECTORY(Y + X)
3. LOAD_NODE_MODULES(X, dirname(Y))
4. 抛出异常:"not found"
LOAD_AS_FILE(X)
1. 如果X是个文件,把 X作为JavaScript 脚本加载,加载完毕后结束
2. 如果X.js是个文件,把X.js 作为JavaScript 脚本加载,加载完毕后结束
3. 如果X.node是个文件,把X.node 作为Node二进制插件加载,加载完毕后结束
LOAD_AS_DIRECTORY(X)
1. 如果 X/package.json文件存在,
   a. 解析X/package.json, 并查找 "main"字段.
   b. 另M = X + (main字段的值)
   c. LOAD_AS_FILE(M)
2. 如果X/index.js文件存在,把 X/index.js作为JavaScript 脚本加载,加载完毕后结束
3. 如果X/index.node文件存在,把load X/index.node作为Node二进制插件加载,加载完毕后结束
LOAD_NODE_MODULES(X, START)
1. 另DIRS=NODE_MODULES_PATHS(START)
2. 对DIRS下的每个目录DIR做如下操作:
   a. LOAD_AS_FILE(DIR/X)
   b. LOAD_AS_DIRECTORY(DIR/X)
NODE_MODULES_PATHS(START)
1. 另PARTS = path split(START)
2. 另ROOT = index of first instance of "node_modules" in PARTS, or 0
3. 另I = count of PARTS - 1
4. 另DIRS = []
5. while I > ROOT,
   a. 如果 PARTS[I] = "node_modules" 则继续后续操作,否则下次循环
   c. DIR = path join(PARTS[0 .. I] + "node_modules")
   b. DIRS = DIRS + DIR
   c. 另I = I - 1
6. 返回DIRS

更多Node.js模块加载详解相关文章请关注PHP中文网!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn