Node.js hat den besten Effekt beim Schreiben von Backends mit JavaScript und es lohnt sich, mehr auszuprobieren. Wenn Sie jedoch einige Funktionen benötigen, die nicht direkt oder sogar Module verwendet werden können, die überhaupt nicht implementiert werden können, können Sie solche Erfolge aus der C/C ++ - Bibliothek einführen? Die Antwort lautet ja. Alles, was Sie tun müssen, ist ein Plugin zu schreiben und andere Ressourcen der Codebasis in Ihrem JavaScript -Code zu verwenden. Beginnen wir die heutige Anfrageberechnung gemeinsam.
einführen
Wie Node.js in der offiziellen Dokumentation sagt, sind Plug-Ins gemeinsam genutzte Objekte, die dynamisch verknüpft werden und JavaScript-Code mit C/C ++-Bibliotheken verbinden können. Dies bedeutet, dass wir auf alles aus der C/C ++ - Bibliothek verweisen und durch das Erstellen von Plugins in node.js einbezogen werden können.
Als Beispiel erstellen wir eine Kapselung für das Standard -STD :: String -Objekt.
Vorbereitung
Bevor wir mit dem Schreiben beginnen, müssen wir sicherstellen, dass wir alle Materialien für die nachfolgende Modulkompilierung vorbereitet haben. Jeder braucht Knotengyp und alle Abhängigkeiten. Sie können den folgenden Befehl verwenden, um den Knotengyp zu installieren:
NPM Installation -g -Knotengyp
In Bezug auf Abhängigkeiten müssen wir die folgenden Projekte für UNIX -Systeme vorbereiten: • Python (erfordert Version 2.7, 3.x kann nicht ordnungsgemäß funktionieren)
• machen
• Ein C ++ - Compiler Toolchain (wie GPP oder G ++)
Auf Ubuntu können Sie beispielsweise den folgenden Befehl verwenden, um alle oben genannten Projekte zu installieren (Python 2.7 hätte vorinstalliert werden müssen):
sudo apt-get installieren Sie Build-Wesentials
In der Windows -Systemumgebung benötigen Sie:
• Python (Version 2.7.3, 3.x kann nicht normal funktionieren)
• Microsoft Visual Studio C ++ 2010 (für Windows XP/Vista)
• Microsoft Visual Studio C ++ 2012 für Windows Desktop (für Windows 7/8)
Um zu betonen, kann die Expressversion von Visual Studio auch normal funktionieren.
Binding.gyp -Datei
Diese Datei wird von Node-GYP verwendet und ist so konzipiert, dass die entsprechende Build-Datei für unser Plugin generiert wird. Sie können hier klicken, um das von Wikipedia bereitgestellte Dokument der .gYP -Datei anzuzeigen. Das Beispiel, das wir heute verwenden möchten, ist sehr einfach. Sie müssen daher nur den folgenden Code verwenden:
{"Ziele": [{"target_name": "stdstring", "Quellen": ["addon.cc", "stdstring.cc"]}]}Wo target_name auf alles gesetzt werden kann, was Ihnen gefällt. Das Quellenarray enthält alle Quelldateien, die das Plug-In verwenden muss. In unserem Beispiel ist Addon.cc auch enthalten, mit dem der Code für die Kompilierung von Plugins und STDString.cc sowie in unserer Kapselungsklasse verwendet wird.
STDStringWrapper Klasse
Der erste Schritt besteht darin, unsere eigene Klasse in der Datei STDString.h zu definieren. Wenn Sie mit der C ++ - Programmierung vertraut sind, werden Sie mit den folgenden zwei Codezeilen definitiv nicht nicht vertraut sein.
#IFNDEF STDSTRING_H #DEFINE STDSTRING_H
Dies gehört zum Standard -Wachmann. Als nächstes müssen wir die folgenden zwei Header in die Kategorie einschließen:
#enthalten
#enthalten
Der erste zielt auf die STD :: String -Klasse ab, während die zweite Akte auf allen inhaltlichen Noten- und V8 -Inhalten enthält.
Nach Abschluss dieses Schritts können wir unsere Klasse deklarieren:
Klasse STDSTRINGWRAPPER: public node :: ObjectWrap {
Für alle Klassen, die wir in das Plugin aufnehmen möchten, müssen wir den Knoten :: ObjectWrap -Klasse erweitern.
Jetzt können wir das Privateigentum dieser Klasse definieren:
privat: std :: string* s_; explizite StdStringWrapper (std :: string s = ""); ~ StdStringWrapper ();
Zusätzlich zu Konstruktoren und analytischen Funktionen müssen wir auch einen Zeiger für Std :: String definieren. Dies ist der Kern dieser Technologie und kann verwendet werden, um die C/C ++ - Code -Basis mit dem Knoten zu verbinden. Wir definieren einen privaten Zeiger für die C/C ++ - Klasse und verwenden diesen Zeiger, um Vorgänge in allen nachfolgenden Methoden zu implementieren.
Jetzt deklarieren wir die Konstruktor -statische Eigenschaft, die Funktionen für die in V8 erstellte Klasse liefert:
statischer V8 :: Persistierter Konstruktor;
Interessierte Freunde können hier klicken, um auf den Plan für die Vorlage Beschreibung zu finden, um weitere Informationen zu erhalten.
Jetzt benötigen wir auch eine neue Methode, die dem oben erwähnten Konstruktor zugewiesen wird, und V8 initialisiert unsere Klasse:
statischer v8 :: neu umgehen (const v8 :: argumente & args);
Jede Funktion, die auf V8 wirkt, sollte den folgenden Anforderungen erfüllen: Verweise auf V8 :: Argumente Objekte und geben einen V8 :: Handle> V8 :: Value> zurück-genau so, wie V8 JavaScript mit schwachem Typ bei der Verwendung von C ++ -Scodierung vom Typ starker Typ handelt.
Danach müssen wir zwei andere Methoden in den Prototyp des Objekts einfügen:
statischer V8 :: Handle add (const v8 :: argumente & args); statischer v8 :: Handlungsübergang (const v8 :: argumente & args);
wobei die Methode toString () es uns ermöglicht, den Wert von s_ anstelle des Werts von [Objektobjekt] zu erhalten, wenn wir ihn mit einer normalen JavaScript -Zeichenfolge verwenden.
Schließlich werden wir die Initialisierungsmethode einführen (diese Methode wird von V8 aufgerufen und der Konstruktorfunktion zugeordnet) und Close Include Guard:
öffentlich: static void init (v8 :: Handlungsexporte); }; #endif
Die Rolle des Exportobjekts im JavaScript -Modul entspricht Modul.exports.
STDSTRING.CC -Datei-, Konstruktor- und Parsingfunktion
Erstellen Sie nun die Datei STDString.cc. Wir müssen zunächst unseren Header einbeziehen:
#include "StdString.h"
Das Folgende definiert die Eigenschaft für den Konstruktor (weil sie zu einer statischen Funktion gehört):
V8 :: Persistent StdStringWrapper :: Konstruktor;
Dieser Konstruktor, der die Klasse dient, wird das S_ -Attribut zuweisen:
STDStringWrapper :: stdStringWrapper (std :: string s) {s_ = new std :: string (s); }Und die Parsingfunktion löscht sie, um den Speicherüberlauf zu vermeiden:
STDStringWrapper :: ~ stdStringWrapper () {delete s_; }Darüber hinaus müssen Sie alle mit neuen zugewiesenen Inhalte löschen, da jedes Mal, wenn diese Situation eine Ausnahme ausführen kann, bitte an die oben genannten Vorgänge oder einen gemeinsam genutzten Zeiger verwenden.
Init -Methode
Diese Methode wird von V8 aufgerufen und soll unsere Klasse initialisieren (den Konstruktor zuweisen und alle Inhalte platzieren, die wir in JavaScript im Exportobjekt verwenden möchten):
void StdStringWrapper :: init (v8 :: Handlungsexporte) {
Zunächst müssen wir eine Funktionsvorlage für unsere neue Methode erstellen:
v8 :: lokal tpl = v8 :: functionTemplate :: new (neu);
Dies ähnelt der neuen Funktion in JavaScript ein bisschen. Sie ermöglicht es uns, unsere eigenen JavaScript -Klassen vorzubereiten.
Jetzt können wir einen Namen für die Funktion entsprechend den tatsächlichen Anforderungen festlegen (wenn Sie diesen Schritt verpassen, befindet sich der Konstruktor im anonymen Zustand, dh der Name ist Funktion somename () {} oder function () {}):
tpl-> setClassName (v8 :: string :: newsymbol ("stdString"));
Wir verwenden v8 :: string :: newsymbol (), um eine spezielle Typ -Zeichenfolge für Eigenschaftsnamen zu erstellen - was ein wenig Zeit für den Motorbetrieb spart.
Danach müssen wir festlegen, wie viele Felder unsere Klasseninstanz enthält:
tpl-> instanCetemplate ()-> setInternalfieldCount (2);
Wir haben zwei Methoden - add () und toString (), sodass wir die Nummer auf 2 einstellen. Jetzt können wir dem Funktionsprototyp unsere eigenen Methoden hinzufügen:
tpl-> prototypetemplate ()-> set (v8 :: string :: newsymbol ("hinzufügen"), v8 :: functionTemplate :: new (add)-> getFunction ());
tpl-> prototypetemplate ()-> set (v8 :: string :: newsymbol ("tostring"), v8 :: functionTemplate :: new (toString)-> getfunction ());
Dieser Teil des Codes sieht ziemlich groß aus, aber solange Sie sorgfältig beobachten, finden Sie die Regeln: Wir verwenden TPL-> Prototypetemplate ()-> set (), um jede Methode hinzuzufügen. Wir verwenden auch v8 :: string :: newsymbol (), um ihnen Namen und FunktionsTemplate bereitzustellen.
Schließlich können wir den Konstruktor in das Exportobjekt in unsere Eigenschaften der Konstruktorklassen einfügen:
constructor = v8 :: persistent :: new (tpl-> getFunction ()); Exporte-> set (v8 :: string :: newsymbol ("STDString"), Konstruktor); }Neue Methode
Wir müssen nun eine Methode definieren, die genauso wie JavaScript Object.Prototype.Constructor funktioniert:
v8 :: Handle StdStringWrapper :: new (const v8 :: argumente & args) {Wir müssen zunächst einen Umfang dafür erstellen:
V8 :: HandlesCope Scope;
Danach können wir die Methode von .isconstructCall () des Args -Objekts verwenden, um zu überprüfen, ob der Konstruktor mit dem neuen Schlüsselwort aufgerufen werden kann:
if (args.isconstructcall ()) {Wenn Sie können, übergeben wir zuerst den Parameter wie folgt an std :: string:
v8 :: string :: utf8Value str (args [0]-> toString ()); std :: string s (*str);
... damit wir es in den Konstruktor unserer eingekapselten Klasse übergeben können:
STDSTRINGWRAPPER* OBJ = New STDStringWrapper (s);
Danach können wir die Methode .Wrap () des Objekts verwenden, das wir zuvor erstellt haben (von Node :: ObjectWrap geerbt), um es dieser Variablen zuzuweisen:
obj-> Wrap (args.this ());
Schließlich können wir dieses neu erstellte Objekt zurückgeben:
return args.this ();
Wenn die Funktion nicht mit neu aufgerufen werden kann, können wir den Konstruktor auch direkt aufrufen. Als nächstes wollen wir eine Konstante für die Parameterzahl festlegen:
} else {const int argc = 1;Jetzt müssen wir ein Array mit unseren eigenen Parametern erstellen:
v8 :: lokal argv [argc] = {args [0]};Geben Sie dann das Ergebnis der Konstruktor -> -Rew -Stanzmethode zum Geltungsbereich über.
return scope.close (Konstruktor-> newinstance (argc, argv)); }}
Methode hinzufügen
Lassen Sie uns nun die Methode hinzufügen, die es jedem ermöglichen soll, dem internen STD :: String des Objekts Inhalte hinzuzufügen:
v8 :: Handle STDStringWrapper :: add (const v8 :: argumente & args) {Zunächst müssen wir einen Bereich für unsere Funktion erstellen und den Parameter in std :: string wie zuvor konvertieren:
V8 :: HandlesCope Scope; v8 :: string :: utf8Value str (args [0]-> toString ()); std :: string s (*str);
Jetzt müssen wir das Objekt auspacken. Wir haben auch diesen Umkehrkapselungsvorgang bereits durchgeführt - diesmal werden wir aus dieser Variablen einen Zeiger auf das Objekt bringen.
STDSTRINGWRAPPER* OBJ = ObjectWrap :: ackrap (args.this ());
Anschließend können wir auf das S_ -Attribut zugreifen und seine .Append () -Methode verwenden:
obj-> s _-> append (s);
Schließlich geben wir den aktuellen Wert des S_ -Attributs zurück (müssen umzusetzen.CLOSE erneut):
return Scope.close (v8 :: string :: new (obj-> s _-> c_str ()));
Da die Methode v8 :: string :: new () nur Zeichenzeiger als Wert akzeptieren kann, müssen wir obj-> s _-> c_str () verwenden, um ihn zu erhalten.
Zu diesem Zeitpunkt sollte in Ihrem Plug-in-Ordner ein Build-Verzeichnis erstellt werden.
prüfen
Jetzt können wir unsere Plug-Ins testen. Erstellen Sie eine Test.js-Datei und die erforderlichen Kompilierungsbibliotheken in unserem Plug-in-Verzeichnis (Sie können die .node-Erweiterung direkt überspringen):
var addon = required ('./ Build/Release/Addon');Erstellen Sie als nächstes eine neue Instanz für unser Objekt:
var test = new Addon.stdString ('Test');Als nächstes tun Sie es, z. B. das Hinzufügen oder Umwandeln in eine Zeichenfolge:
test.add ('!'); console.log ('test/' s Inhalt: %s ', test);Nach dem Laufen sollten Sie die folgenden Ausführungsergebnisse in der Konsole sehen:
abschließend
Ich hoffe, dass Sie nach dem Lesen dieses Tutorials Ihre Bedenken zerstreuen und das Erstellen und Testen von kundenspezifischen Node.Js-Plug-Ins basierend auf C/C ++-Bibliotheken als sehr schwierige Aufgabe betrachten können. Sie können diese Technologie verwenden, um fast jede C/C ++ - Bibliothek in node.js. Wenn Sie möchten, können Sie dem Plug-In auch mehr Funktionen entsprechend den tatsächlichen Anforderungen hinzufügen. STD :: String bietet viele Methoden, und wir können sie als Übungsmaterialien verwenden.
Praktische Links
Interessierte Freunde können die folgenden Links überprüfen, um weitere Ressourcen und Details im Zusammenhang mit Node.JS-Plug-in-Entwicklung, V8- und C-Ereignisschleifungsbibliotheken zu beziehen.
• Node.js Plugin -Dokumentation
• V8 -Dokumentation
• Libuv (C Event Loop Library) aus GitHub
Englisch: http://code.tutsplus.com/tutorials/writing-nodejs-addons-cms-21771