Teilen Sie den ersten Artikel über NodeJS – allgemeine Kenntnisse über Javascript und den Übergang vom Javascript-Entwickler zum NodeJS-Entwickler (das spezifische Framework wird nicht vorgestellt). Bevor Sie diesen Artikel lesen, hoffe ich, dass Sie ein gewisses Vorwissen über Javascript haben.
Javascript ist eine interpretierte Sprache, die auf Prototypmodellen basiert. Die Interpretation wird später in NodeJS besprochen. Die Prototypenkette ist eine der objektorientierten Implementierungsmethoden von Javascript vor ES6. Der in ES6 unterstützten Klasse wurde eine neue Implementierungsmethode hinzugefügt. Alles in Javascript ist ein Objekt, einschließlich „Klassen“. Diejenigen, die mit der Ruby/Python-Metaprogrammierung vertraut sind, werden dies möglicherweise als sehr vertraut empfinden, und Javascript kann leicht eine Methode zur dynamischen Generierung von Klassen implementieren.
1. Einfache „Klasse“ basierend auf der Prototypenkette implementiert
var Person = function(name){ this.name = name; }; Person.staticSay = function(name){ console.log('Hello ' + name); }; Person.prototype.sayHi = function(){ Person.staticSay(this.name); }
Erwähnen Sie einige allgemeine Spezifikationen, zum Beispiel, dass alle Methoden in Javascript in Kamelbuchstaben benannt werden, einfache Anführungszeichen bevorzugt werden, zwei Leerzeichen verwendet werden usw. Weitere Spezifikationen finden Sie unter https://github.com /airbnb/ javascript.
staticSay im Code ist eine statische Methode, das heißt, sie kann nur über Person.staticSay aufgerufen werden. Wenn die obige Person eine Instanz generiert, zum Beispiel var vincent = new Person('vincent');, erbt vincent automatisch alle Methoden von Person.prototype (dies bezieht sich im Code auf den aktuellen Kontext, bei dem es sich um den obigen vincent handelt). .
Gleichzeitig können Sie dem Objekt vincent auch dynamisch Methoden hinzufügen, z. B. den folgenden Code:
var vincent = new Person('vincent') vincent.tellName = function(){ console.log('Hi, i\'m am' + this.name) };
Wenn Sie dann die Vererbung simulieren müssen, müssen Sie am Prototyp arbeiten. Um dies zu erreichen, wird im Folgenden beispielsweise Worker.prototype = new Person() verwendet. Alle Methoden und Eigenschaften des von new Person() zurückgegebenen Instanzobjekts werden dem Prototyp zugewiesen, wodurch eine verdeckte Vererbung simuliert wird. Diese Methode sucht letztendlich Schicht für Schicht nach dem Inhalt des Prototyps (da sich die Methoden jeder Instanz im Prototyp befinden und bis zum Objekt reichen). Natürlich können Sie die Vererbung auch simulieren, indem Sie dem Prototyp durch Traversierung Werte zuweisen.
2. Kontextwechsel
Der intuitivste Ausdruck des Kontexts ist dieser im Codeblock, der normalerweise in der objektorientierten Programmierung verwendet wird, um auf die entsprechende Instanz zu verweisen, die von der aktuellen „Klasse“ generiert wird und mit self in anderen Sprachen übereinstimmt.
Um das obige Beispiel weiter zu verwenden, wurde oben eine Person.prototype.sayHi-Methode implementiert. Jetzt habe ich ein neues Objekt, der Code lautet wie folgt:
var Cat = function(name){ this.name = name; } var c = new Cat('tomcat');
Was ist, wenn ich eines Tages plötzlich möchte, dass die Katze sich wie ein Mensch vorstellt? Er hat nicht die SayHi-Methode. Aber Sie können die menschliche sayHi-Methode über console.log(Person.prototype.sayHi) erhalten. Wie können Katzen sie auch verwenden?
Javascript verfügt über zwei Methoden: Aufruf und Anwendung. Der Unterschied besteht darin, dass die Parameter unterschiedlich sind (Google selbst) und ihre Funktion darin besteht, den Kontext zu wechseln. Vereinfacht ausgedrückt können Sie dies in der Funktion Person.prototype.sayHi in andere Objekte ändern. Verwendung: Person.prototype.sayHi.call(c).
Ist das praktisch? Zum Beispiel das folgende Szenario:
var doSomething = function(){ var persons = arguments; };
In der obigen Funktion werden alle Parameter über die Schlüsselwortargumente abgerufen, um eine unbegrenzte Anzahl von Parametern zu unterstützen. Jetzt wollen wir einige Methoden, die ursprünglich zum Array-Typ gehören, auf Personen anwenden. Hier können Sie die Kontextumschaltung nutzen:
var doSomething = function(){ var persons = arguments; // 使用 Array 的 slice 方法,将 arguments 对象转变为 Array 实例 var persons_arr = Array.prototype.slice.call(arguments); };
3. Schließung
Beginnen wir mit einem allgemeinen Code
for (var i = 0; i < 3; i ++){ setTimeout(function(){ console.log(i); }, i) }
Was wird dabei herauskommen? 0 1 2 nacheinander ausgeben? Die tatsächliche Situation ist, dass die for-Schleife beendet ist, wenn setTimeout den Rückruf zum ersten Mal ausführt, was bedeutet, dass i zu diesem Zeitpunkt bereits 3 ist, was dazu führt, dass das endgültige Ausgabeergebnis 3 3 3 ist.
Wenn Sie eine Variable schützen müssen, damit sie nicht vom umgebenden Code beeinflusst wird, müssen Sie möglicherweise einen Abschluss in Betracht ziehen – einen Codeblock mit einem geschlossenen Gültigkeitsbereich.
for (var i = 0; i < 3; i ++){ +function(i){ setTimeout(function(){ console.log(i); }, i) }(i) }
Hey, wofür ist es? Wenn es einen anderen Weg gibt, es zu erreichen, googeln Sie es bitte selbst. Der Bereich von i innerhalb des Abschlusses ist ein geschlossener Bereich, sodass i innerhalb des Abschlusses letztendlich nicht durch externe Ausführung geändert wurde, sodass 0 1 2 erfolgreich ausgegeben werden kann.
Kurze Einführung in einige Funktionen von Javascript, Schlüsselwort-Prototypenkette, Aufruf und Anwendung sowie Argumentschlüsselwörter. Weitere Vorschläge finden Sie in Büchern wie dem maßgeblichen Leitfaden oder einem schnellen Verständnis der Grundtypen und der Merkmale jedes Typs. Verfahren. Es gibt einige weitere magische Codes, z. B. das Abrufen der Zeichenfolge des aktuellen Codes und das anschließende Verarbeiten, um den gewünschten Inhalt zu erhalten. Verwenden von Gettern und Settern, um einige spezielle Vorgänge auszuführen, wenn der Benutzer Objekteigenschaften abruft oder ihnen Werte zuweist. usw.
4. Der Unterschied zwischen NodeJS- und Javascript-Entwicklung
In diesem Abschnitt werden hauptsächlich die Grundkenntnisse des erforderlichen Ladens vorgestellt. Führen Sie zunächst etwas Code ein:
// a.js module.exports = { name: "a", doSomething: function(){ return "something"; } } // b.js var a = require('./a') global.a_name = a.name; // c.js require('./b'); console.log(a_name) // 执行后打印 a
Was passiert, wenn wir Knoten c.js ausführen?
require ist das Node-Schlüsselwort. Obwohl NodeJS dafür bekannt ist, asynchron zu sein, blockiert es. Andernfalls kann es vorkommen, dass die Ausführung des folgenden Codes bereits begonnen hat, bevor andere Module geladen wurden.
Die Methode require.resolve() wird verwendet, um den tatsächlichen Pfad der Datei herauszufinden, auf die Sie verweisen. Nachdem Sie dies herausgefunden haben, prüft Nodejs, ob ein Cache vorhanden ist Datei und analysieren Sie sie. In diesem Fall wird der ausgeführte Code in einer js-Datei normalerweise nur dann ausgeführt, wenn er zum ersten Mal benötigt wird. (Tipp. require.cache kann bei Bedarf manuell gelöscht und dann bis zu einem gewissen Grad mehrmals ausgeführt werden)
Wenn b.js mit der Ausführung beginnt, muss es zuerst a.js laden. module.exports teilt Nodejs mit, was diese Datei der Außenwelt zugänglich macht. Beispielsweise macht a.js ein Objekt verfügbar, einschließlich des Namensattributs und des doSomething-Methode. Dann ist die Variable a in b.js tatsächlich dieses Objekt.
Nachdem Sie a.js ausgeführt haben, kehren Sie weiterhin zu b.js zurück. Global.a_name entspricht der Deklaration einer globalen Variablen. Dies hat einen ähnlichen Effekt wie window.a_name = a.name im Frontend.
Der letzte Prozess ist abgeschlossen und c.js führt den Ausgabewert aus.
5. Das zugrunde liegende Prinzip der Asynchronität
NodeJS kann den Leuten leicht eine Illusion der Verwendung vermitteln, das heißt, selbst nach längerem Schreiben wissen Sie möglicherweise nicht, wie die zugrunde liegende Asynchronität implementiert ist. (Das folgende Verständnis stammt hauptsächlich aus dem Verständnis von Asyncio in Python3.4. Wenn Fehler auftreten, weisen Sie bitte darauf hin.)
Das zugrunde liegende Libev von NodeJS verwendet IOCP unter Windows und AIO-basiertes Libeio unter *nix, um eine asynchrone Implementierung zu erreichen. Durch die Technologie auf Systemebene wird schließlich ein Ziel erreicht: Die Anwendung initiiert eine asynchrone Anforderung. Nachdem das System die Ausführung abgeschlossen hat, benachrichtigt das System die Anwendung schließlich über den Abschluss der Verarbeitung. Während dieses Prozesses kann die Anwendung die vorherige Verarbeitung anhalten/in den Thread-Pool verschieben, um auf die Ausführung zu warten, und die Anwendung kann in diesem Zeitraum andere Aufgaben ausführen.
Der gesamte Vorgang läuft über die Ereignisschleife auf Systemebene ab. Python bietet beispielsweise ähnliche Methoden wie run_until und run_forever, um sicherzustellen, dass das Programm nicht vor der asynchronen Ausführung beendet wird. Stellen Sie sich den gesamten asynchronen Betrieb als eine Werkstatt vor, die ständig in Betrieb ist. Die Maschinen in der Werkstatt sind dafür verantwortlich, die Pakete zu überprüfen und zu stempeln. Die Arbeiter nehmen ein Paket entgegen, legen es mit dem entsprechenden Etikett ab und bringen es anschließend in die Werkstatt zurück Die Bearbeitung erfolgt durch den Werker anhand des zuvor auf dem Paket angebrachten Etiketts und des von der Werkstatt angebrachten Etiketts. Der Arbeiter muss nicht auf die Inspektion des Pakets warten, bevor er mit dem nächsten fortfährt. Er muss lediglich die einfache Bearbeitung entgegennehmen und sie dann zur Inspektion in die Werkstatt bringen. Anschließend wartet er darauf, dass ihm die Werkstatt zu einem bestimmten Zeitpunkt ein Paket zurückgibt, und fährt dann mit dem nächsten Schritt fort.
Derzeit führen wir hauptsächlich nur einige Sprachkenntnisse ein, aber nur diese sind noch weit von der Entwicklung eines vollständigen Webs entfernt, das später eingeführt wird. Einschließlich Redis, Nginx, Testtreiber usw.
Das Obige ist der gesamte Inhalt dieses Artikels. Ich hoffe, er gefällt Ihnen allen.