Dieser Artikel fasst die vier wichtigsten Node.js-Punkte für Entwickler zusammen.
1. Nicht blockierende oder asynchrone E/A
Da Node.js ein serverseitiges Framework ist, besteht eine seiner Hauptaufgaben darin, Browseranfragen zu verarbeiten. In einem herkömmlichen E/A-System wird jede Anfrage ausgegeben, nachdem die vorherige Anfrage eingegangen ist. Man nennt dies also blockierende E/A. Der Server blockiert andere Anfragen zur Verarbeitung der aktuellen Anfrage, wodurch der Browser wartet.
Node.js verarbeitet E/A nicht auf diese Weise. Wenn die Verarbeitung einer Anfrage lange dauert, sendet Node.js die Anfrage an eine Ereignisschleife und fährt mit der Verarbeitung der nächsten Anfrage im Aufrufstapel fort. Wenn die verzögerte Anfrage verarbeitet wird, wird Node.js benachrichtigt und der Browser antwortet.
Im Folgenden wird ein Beispiel zur Veranschaulichung verwendet.
Blockieren von E/A
// take order for table 1 and wait... var order1 = orderBlocking(['Coke', 'Iced Tea']); // once order is ready, take order back to table. serveOrder(order1); // once order is delivered, move on to another table. // take order for table 2 and wait... var order2 = orderBlocking(['Coke', 'Water']); // once order is ready, take order back to table. serveOrder(order2); // once order is delivered, move on to another table. // take order for table 3 and wait... var order3 = orderBlocking(['Iced Tea', 'Water']); // once order is ready, take order back to table. serveOrder(order3); // once order is delivered, move on to another table.
In diesem Restaurantbeispiel erhält der Kellner die Menüanweisungen, wartet auf die Verarbeitung der Mahlzeit und bringt die Mahlzeit dann an den Tisch, nachdem die Mahlzeit verarbeitet wurde. Während der Kellner darauf wartet, dass sein Essen verarbeitet wird, lehnt er die Menübestellungen anderer Kunden ab.
Nicht blockierende E/A
// take order for table 1 and move on... orderNonBlocking(['Coke', 'Iced Tea'], function(drinks){ return serveOrder(drinks); }); // take order for table 2 and move on... orderNonBlocking(['Beer', 'Whiskey'], function(drinks){ return serveOrder(drinks); }); // take order for table 3 and move on... orderNonBlocking(['Hamburger', 'Pizza'], function(food){ return serveOrder(food); });
Im nicht blockierenden Modus informiert der Kellner den Koch über die erhaltenen Menüanweisungen und erhält dann die Anweisungen für den nächsten Tisch. Wenn das Essen des ersten Tisches verarbeitet ist, serviert er die Gerichte für diesen Tisch und erhält dann weiterhin Anweisungen von anderen Gästen. Auf diese Weise verschwendet der Kellner keine Zeit damit, Anweisungen zu blockieren.
2. Prototyp
Prototyp ist ein komplexes Konzept in JS. In typischen Vererbungsmechanismussprachen wie Java oder C müssen Sie zum Erreichen der Wiederverwendung von Code zunächst eine Klasse erstellen und dann Objekte über diese generieren oder Objekte über Klassenerweiterungen generieren. Aber es gibt kein ähnliches Klassenkonzept in JS. Nachdem Sie ein Objekt in JS erstellt haben, müssen Sie das Objekt erweitern oder ein neues Objekt darüber erstellen. Dies wird als prototypische Vererbung bezeichnet.
Jedes JS-Objekt ist mit einem Prototypobjekt verbunden und erbt die Eigenschaften dieses Objekts. Jedes Objekt ist einem vordefinierten JS Object.prototype zugeordnet. Wenn Sie über obj.propName oder obj['propName'> nach Objekteigenschaften suchen, die Suche jedoch fehlschlägt, können Sie versuchen, über obj.hasOwnProperty('propName') zu suchen. Die JS-Laufzeit wird im Prototyp gefunden Objekt. Wenn die Eigenschaft in der Prototypenkette nicht vorhanden ist, wird ein undefinierter Wert zurückgegeben.
Lassen Sie uns das anhand des folgenden Beispiels veranschaulichen:
if (typeof Object.create !== 'function') { Object.create = function (o) { var F = function () {}; F.prototype = o; return new F(); }; var otherPerson = Object.create(person);
Wenn Sie ein neues Objekt erstellen, müssen Sie ein prototypbasiertes Objekt auswählen. Hier haben wir der Objektfunktion eine Erstellungsmethode hinzugefügt. Die Methode create erstellt ein Objekt basierend auf einem anderen Objekt und übergibt es als Parameter.
Wenn wir ein neues Objekt ändern, bleibt sein Prototyp unverändert. Wenn wir jedoch ein Prototypobjekt ändern, wirkt sich die Änderung auf alle Objekte aus, die auf diesem Prototyp basieren.
3. Module
Wenn Sie jemals Pakete in Java verwendet haben, sind die Node.js-Komponenten ähnlich. Wenn nicht, machen Sie sich keine Sorgen; Komponenten sind eigentlich einfache JS-Dateien, die zur Implementierung bestimmter Funktionen verwendet werden. Der Zweck des Komponentenmusters besteht darin, Ihnen die Arbeit zu erleichtern. Um Komponenten verwenden zu können, müssen Sie JS-Dateien importieren, genau wie Sie Pakete in JAVA importieren. Es gibt zwei Arten von Komponenten in Node.js
Kernmodule – Kernmodule werden in Verbindung mit der Node.js-Bibliothek vorkompiliert. Sein Zweck besteht darin, von Programmierern häufig verwendete Funktionen zu öffnen und Doppelarbeit zu vermeiden. Zu den allgemeinen Kernkomponenten gehören HTTP, URL, EREIGNISSE, DATEISYSTEM usw.
Benutzerdefinierte Module – Benutzerdefinierte Module sind Komponenten, die Benutzern zur Implementierung bestimmter Funktionen bereitgestellt werden. Wenn die Kernkomponenten nicht ausreichen, um die Anforderungen von Programmierern zu erfüllen, können benutzerdefinierte Komponenten nützlich sein.
Komponenten werden über die Funktion require extrahiert. Wenn es sich um eine Kernkomponente handelt, ist der Parameter der Komponentenname. Wenn es sich um eine benutzerdefinierte Komponente handelt, ist der Parameter deren Komponentenpfad im Dateisystem. Zum Beispiel:
// extract a core module like this var http = require('http); // extract a user defined module like this var something = require('./folder1/folder2/folder3/something.js');
4. 回调(Callbacks)
在JS中,函数是第一类对象。也就是说你可以像对常规对象那样对函数进行所有操作。例如指派函数到一个变量,把这些作为参数传给方法,把它们声明为对象的属性,甚至是把它们从函数里返回。
回调在JS中是异步函数,可以作为参数传递给其它函数或从其它函数里执行或返回而后再执行。这是回调的基本概念。
当我们把一个回调函数作为参数传递给另外的函数时,我们传递的仅仅是函数的定义;换言之,我们不会知道回调函数的执行时间。这完全依赖于回调函数机制。它会在稍后某个时间点进行回调调用。这是Node.js的非阻塞或异步行为的基本概念,可用下例进行说明:
setTimeout(function() { console.log("world"); }, 2000) console.log("hello");
这是一个最简单的调用。我们把一个匿名函数作为参数进行传递,作用是为setTimeout函数进行控制台的输出记录登记。因为这仅仅是个函数定义,我们不知道函数何时会被执行。这取决于setTimeout函数的second参数,即2S后。
首先,second记录语句记录了对控制台的输出,2S后,在回调函数中的记录语句记录了输出的内容。
// output hello world
写在最后
以上4点对Node.js开发者来说是要彻底理解和掌握的,建议多动手来好好体会这4个要点的含义。