Node.js tiene el mejor efecto al escribir backends usando JavaScript, y vale la pena intentarlo más. Sin embargo, si necesita algunas funciones que no se pueden usar directamente o incluso módulos que no se pueden implementar en absoluto, ¿puede introducir tales logros de la biblioteca C/C ++? La respuesta es sí. Todo lo que tiene que hacer es escribir un complemento y usar otros recursos básicos de código en su código JavaScript. Comencemos el viaje de consulta de hoy juntos.
introducir
Como dice Node.js en la documentación oficial, los complementos son objetos compartidos que enlazan dinámicamente, lo que puede conectar el código JavaScript con bibliotecas C/C ++. Esto significa que podemos hacer referencia a cualquier cosa de la biblioteca C/C ++ e incorporarla a Node.js creando complementos.
Como ejemplo, crearemos una encapsulación para el objeto STD :: String estándar.
Preparación
Antes de comenzar a escribir, debemos asegurarnos de haber preparado todos los materiales necesarios para la compilación de módulos posteriores. Todos necesitan Node-GYP y todas las dependencias. Puede usar el siguiente comando para instalar el nodo-gyp:
NPM instalación -g nodo -gyp
En términos de dependencias, necesitamos preparar los siguientes proyectos para sistemas UNIX: • Python (requiere la versión 2.7, 3.x no puede funcionar correctamente)
• hacer
• Una cadena de herramientas del compilador C ++ (como GPP o G ++)
Por ejemplo, en Ubuntu, puede usar el siguiente comando para instalar todos los proyectos anteriores (Python 2.7 debería haber sido preinstalado):
sudo apt-get instalar esencials de construcción
En el entorno del sistema de Windows, lo que necesita es:
• Python (versión 2.7.3, 3.x no puede funcionar normalmente)
• Microsoft Visual Studio C ++ 2010 (para Windows XP/Vista)
• Microsoft Visual Studio C ++ 2012 para Windows Desktop (para Windows 7/8)
Para enfatizar, la versión expresa de Visual Studio también puede funcionar normalmente.
archivo binding.gyp
Este archivo es utilizado por Node-GYP y está diseñado para generar el archivo de compilación apropiado para nuestro complemento. Puede hacer clic aquí para ver el documento de descripción del archivo .gyp proporcionado por Wikipedia, pero el ejemplo que queremos usar hoy es muy simple, por lo que solo necesita usar el siguiente código:
{"Targets": [{"target_name": "stdstring", "fuentes": ["addon.cc", "stdstring.cc"]}]}Donde Target_name se puede configurar en cualquier cosa que desee. La matriz de fuentes contiene todos los archivos de origen que el complemento debe usar. En nuestro ejemplo, también se incluye addon.cc, que se utiliza para acomodar el código necesario para compilar complementos y stdstring.cc, más nuestra clase de encapsulación.
Clase de stdstringwrapper
El primer paso es definir nuestra propia clase en el archivo stdstring.h. Si está familiarizado con la programación C ++, definitivamente no estará familiarizado con las siguientes dos líneas de código.
#ifndef stdstring_h #define stdstring_h
Esto pertenece al estándar incluye guardia. A continuación, debemos incluir los siguientes dos encabezados en la categoría de incluir:
#incluir
#incluir
El primero está dirigido a la clase STD :: String, mientras que el segundo incluye actos en todos los contenidos relacionados con Node y V8.
Después de completar este paso, podemos declarar nuestra clase:
clase stdstringwrapper: public nodo :: objectWrap {
Para todas las clases que tenemos la intención de incluir en el complemento, debemos extender la clase Node :: ObjectWrap.
Ahora podemos comenzar a definir la propiedad privada de esta clase:
Privado: std :: string* s_; STDStringWrapper explícito (std :: string s = ""); ~ Stdstringwrapper ();
Además de constructores y funciones analíticas, también necesitamos definir un puntero para std :: string. Este es el núcleo de esta tecnología y se puede utilizar para conectar la base del código C/C ++ al nodo: definimos un puntero privado para la clase C/C ++ y utilizaremos este puntero para implementar operaciones en todos los métodos posteriores.
Ahora declaramos la propiedad estática del constructor, que proporcionará funciones para la clase que creamos en V8:
V8 estático :: Constructor persistente;
Los amigos interesados pueden hacer clic aquí para consultar el plan de descripción de la plantilla para obtener más detalles.
Ahora también necesitamos un nuevo método, que se asignará al constructor mencionado anteriormente, y V8 inicializará nuestra clase:
static v8 :: manejar nuevo (const v8 :: argumentos y args);
Cada función que actúe en V8 debe seguir los siguientes requisitos: aceptará referencias a V8 :: Objetos de argumentos y devolverá un V8 :: Handle> V8 :: Value>-Así es exactamente cómo V8 trata con JavaScript de tipo débil cuando se usa la codificación de C ++ de tipo fuerte.
Después de esto, necesitamos insertar otros dos métodos en el prototipo del objeto:
static v8 :: manejar add (const v8 :: argumentos y args); static v8 :: manejar tostring (const v8 :: argumentos y args);
donde el método toString () nos permite obtener el valor de S_ en lugar del valor de [objeto de objeto] cuando lo usa con una cadena JavaScript normal.
Finalmente, introduciremos el método de inicialización (este método se llamará por V8 y se asignará a la función del constructor) e cierre incluir Guard:
público: static void init (v8 :: manejar exportaciones); }; #endif
El papel del objeto de exportación en el módulo JavaScript es equivalente a módulo.exports.
archivo, constructor y función de archivo stdstring.cc
Ahora cree el archivo stdstring.cc. Primero tenemos que incluir nuestro encabezado:
#Include "stdstring.h"
A continuación se define la propiedad para el constructor (porque pertenece a una función estática):
v8 :: persistente stdstringwrapper :: constructor;
Este constructor que sirve a la clase asignará el atributo S_:
Stdstringwrapper :: stdstringwrapper (std :: string s) {s_ = new std :: string (s); }Y la función de análisis la eliminará para evitar el desbordamiento de la memoria:
Stdstringwrapper :: ~ ststringwrapper () {eliminar s_; }Además, debe eliminar todo el contenido asignado con nuevo, porque cada vez que dicha situación puede causar una excepción, recuerde las operaciones anteriores o utilizar un puntero compartido.
Método init
V8 llamará a este método y tiene la intención de inicializar nuestra clase (asigne el constructor y coloque todo el contenido que pretendemos usar en JavaScript en el objeto de exportaciones)::
void stdstringwrapper :: init (v8 :: manejar exportaciones) {
Primero, necesitamos crear una plantilla de función para nuestro nuevo método:
v8 :: local tpl = v8 :: functionTemplate :: nuevo (nuevo);
Esto es un poco similar a la nueva función en JavaScript: nos permite preparar nuestras propias clases de JavaScript.
Ahora podemos establecer un nombre para la función de acuerdo con las necesidades reales (si se pierde este paso, el constructor estará en estado anónimo, es decir, el nombre es la función somename () {} o function () {})::
tpl-> setClassName (v8 :: string :: newsymbol ("stdstring"));
Usamos V8 :: String :: Newsymbol () para crear una cadena de tipo especial para nombres de propiedades, que ahorra un poco de tiempo para la operación del motor.
Después de esto, necesitamos establecer cuántos campos contiene nuestra instancia de clase:
tpl-> instancETemplate ()-> setInternalfieldCount (2);
Tenemos dos métodos: add () y toString (), por lo que establecemos el número en 2. Ahora podemos agregar nuestros propios métodos al prototipo de funciones:
tpl-> prototypeTemplate ()-> set (v8 :: string :: newsymbol ("agregar"), v8 :: functionTemplate :: new (add)-> getFunction ());
tpl-> prototypeTemplate ()-> set (v8 :: string :: newyymbol ("toString"), v8 :: functionEmplate :: new (toString)-> getFunction ());
Esta parte del código se ve bastante grande, pero siempre que observe cuidadosamente, encontrará las reglas: usamos tpl-> prototypeTemplate ()-> set () para agregar cada método. También usamos V8 :: String :: Newsymbol () para proporcionarles nombres y functSeMplate.
Finalmente, podemos colocar el constructor en el objeto de exportación dentro de nuestras propiedades de clase de constructor:
constructor = v8 :: persistente :: nuevo (tpl-> getFunction ()); Exports-> set (v8 :: string :: newsymbol ("stdstring"), constructor); }Nuevo método
Ahora lo que tenemos que hacer es definir un método que funcione igual que JavaScript Object.Prototype.Constructor:
v8 :: manejar stdstringwrapper :: new (const v8 :: argumentos y args) {Primero necesitamos crear un alcance para ello:
V8 :: alcance de manejo;
Después de esto, podemos usar el método .IsconstructCall () del objeto Args para verificar si el constructor se puede llamar utilizando la nueva palabra clave:
if (argS.IsConstructCall ()) {Si puede, primero pasamos el parámetro a std :: string de la siguiente manera:
v8 :: string :: utf8Value str (args [0]-> toString ()); std :: string s (*str);
... para que podamos pasarlo al constructor de nuestra clase encapsulada:
Stdstringwrapper* obj = nuevo stdstringwrapper (s);
Después de esto, podemos usar el método .wrap () del objeto que creamos anteriormente (heredado de nodo :: objectWrap) para asignarlo a esta variable:
obj-> wrap (args.this ());
Finalmente, podemos devolver este objeto recién creado:
regreso args.this ();
Si no se puede llamar a la función con nuevo, también podemos llamar al constructor directamente. A continuación, lo que queremos hacer es establecer una constante para el recuento de parámetros:
} else {const int argc = 1;Ahora necesitamos crear una matriz usando nuestros propios parámetros:
v8 :: local argv [argc] = {args [0]};Luego pase el resultado del método de constructor-> NewInstance para alcanzar.
return scope.close (constructor-> newInstance (argc, argv)); }}
Añadir método
Ahora creemos el método ADD, que está destinado a permitir que todos agregen contenido a la STD interna del objeto :: String:
v8 :: manejar stdstringwrapper :: add (const v8 :: argumentos y args) {Primero, necesitamos crear un rango para nuestra función y convertir el parámetro en std :: string como antes:
V8 :: alcance de manejo; v8 :: string :: utf8Value str (args [0]-> toString ()); std :: string s (*str);
Ahora necesitamos desempacar el objeto. También hemos realizado esta operación de encapsulación inversa antes: esta vez vamos a obtener un puntero al objeto de esta variable.
Stdstringwrapper* obj = objectWrap :: Unwrap (args.this ());
Luego podemos acceder al atributo S_ y usar su método .append ():
obj-> s _-> append (s);
Finalmente, devolvemos el valor actual del atributo S_ (necesita usar Scope.clar nuevamente):
return scope.close (v8 :: string :: new (obj-> s _-> c_str ()));
Dado que el método v8 :: string :: new () solo puede aceptar el puntero de char como un valor, necesitamos usar obj-> s _-> c_str () para obtenerlo.
En este momento, se debe crear un directorio de compilación en su carpeta de complemento.
prueba
Ahora podemos probar nuestros complementos. Cree un archivo test.js y bibliotecas de compilación necesarias en nuestro directorio de complemento (puede omitir directamente la extensión .node):
var addon = request ('./ build/rotes/addon');A continuación, cree una nueva instancia para nuestro objeto:
var test = new Addon.stdString ('test');A continuación, hágalo, como agregarlo o convertirlo en una cadena:
test.add ('!'); console.log ('Test/' S Contenido: %S ', Test);Después de ejecutar, debería ver los siguientes resultados de ejecución en la consola:
en conclusión
Espero que después de leer este tutorial, pueda disipar sus inquietudes y considerar la creación y prueba de complementos de nodo.js personalizados basados en bibliotecas C/C ++ como una tarea muy difícil. Puede usar esta tecnología para introducir fácilmente casi cualquier biblioteca C/C ++ en Node.js. Si lo desea, también puede agregar más funciones al complemento de acuerdo con las necesidades reales. STD :: String proporciona muchos métodos, y podemos usarlos como materiales de ejercicio.
Enlaces prácticos
Los amigos interesados pueden consultar los siguientes enlaces para obtener más recursos y detalles relacionados con el desarrollo del complemento Node.js, las bibliotecas de bucle de eventos V8 y C.
• Documentación del complemento Node.js
• Documentación V8
• Libuv (B Biblioteca de bucle de eventos C), de Github
Inglés: http://code.tutsplus.com/tutorials/writing-nodejs-addons-cms-21771