O Node.js tem o melhor efeito ao escrever back -ends usando JavaScript, e vale a pena tentar mais. No entanto, se você precisar de algumas funções que não podem ser usadas diretamente ou mesmo módulos que não podem ser implementados, você pode introduzir essas conquistas na biblioteca C/C ++? A resposta é sim. Tudo o que você precisa fazer é escrever um plug -in e usar outros recursos base de código no seu código JavaScript. Vamos começar a jornada de inquérito de hoje juntos.
introduzir
Como o Node.js diz na documentação oficial, os plug-ins são objetos compartilhados que vinculam dinamicamente, que podem conectar o código JavaScript às bibliotecas C/C ++. Isso significa que podemos fazer referência a qualquer coisa da biblioteca C/C ++ e incorporá -la ao Node.js criando plugins.
Como exemplo, criaremos um encapsulamento para o objeto STD :: String padrão.
Preparação
Antes de começarmos a escrever, precisamos garantir que preparemos todos os materiais necessários para a compilação subsequente do módulo. Todo mundo precisa de GYP de nó e de todas as dependências. Você pode usar o seguinte comando para instalar o Node-GYP:
NPM Install -g Node -GYP
Em termos de dependências, precisamos preparar os seguintes projetos para sistemas Unix: • Python (requer a versão 2.7, 3.x não pode funcionar corretamente)
• fazer
• Uma cadeia de ferramentas do compilador C ++ (como GPP ou G ++)
Por exemplo, no Ubuntu, você pode usar o seguinte comando para instalar todos os projetos acima (o Python 2.7 deveria ter sido pré-instalado):
sudo apt-get Install Build-SESTIALS
No ambiente do sistema Windows, o que você precisa é:
• Python (versão 2.7.3, 3.x não pode 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, a versão expressa do Visual Studio também pode funcionar normalmente.
arquivo binding.gyp
Este arquivo é usado pelo Node-GYP e foi projetado para gerar o arquivo de compilação apropriado para o nosso plug-in. Você pode clicar aqui para visualizar o documento .gyp arquivo de descrição fornecido pela Wikipedia, mas o exemplo que queremos usar hoje é muito simples, então você só precisa usar o seguinte código:
{"Targets": [{"Target_name": "stdstring", "fontes": ["addon.cc", "stdstring.cc"]}]}Onde Target_name pode ser definido como o que você quiser. A matriz de fontes contém todos os arquivos de origem que o plug-in precisa usar. Em nosso exemplo, o addon.cc também está incluído, que é usado para acomodar o código necessário para compilar plugins e stdstring.cc, além de nossa classe de encapsulamento.
Classe StdstringWrapper
A primeira etapa é definir nossa própria classe no arquivo stdstring.h. Se você estiver familiarizado com a programação C ++, definitivamente não estará familiarizado com as duas linhas de código a seguir.
#ifndef stdstring_h #define stdstring_h
Isso pertence ao padrão inclui guarda. Em seguida, precisamos incluir os dois cabeçalhos a seguir na categoria Incluir:
#include
#include
O primeiro é destinado à classe STD :: String, enquanto o segundo inclui atos em todos os nó e conteúdo relacionado a V8.
Depois que esta etapa é concluída, podemos declarar nossa classe:
classe stdstringwrapper: public node :: objectwrap {
Para todas as classes que pretendemos incluir no plug -in, devemos estender a classe Node :: ObjectWrap.
Agora podemos começar a definir a propriedade privada desta classe:
Privado: std :: string* s_; STDSTRINGWRAPPER explícito (std :: string s = ""); ~ StdstringWrapper ();
Além dos construtores e funções analíticas, também precisamos definir um ponteiro para STD :: String. Esse é o núcleo dessa tecnologia e pode ser usado para conectar a base de código C/C ++ ao nó - definimos um ponteiro privado para a classe C/C ++ e usaremos esse ponteiro para implementar operações em todos os métodos subsequentes.
Agora declaramos a propriedade estática do construtor, que fornecerá funções para a aula que criamos no V8:
estático V8 :: construtor persistente;
Os amigos interessados podem clicar aqui para consultar o plano de descrição do modelo para obter mais detalhes.
Agora, também precisamos de um novo método, que será atribuído ao construtor mencionado acima, e o V8 inicializará nossa classe:
estático v8 :: lide novo (const v8 :: argumentos e args);
Toda função que atua no V8 deve seguir os seguintes requisitos: aceitará referências a objetos V8 :: Argumentos e retornará um V8 :: Handle> V8 :: Value>-É exatamente como o V8 lida com JavaScript de tipo fraco ao usar a codificação C ++ de tipo forte.
Depois disso, precisamos inserir outros dois métodos no protótipo do objeto:
estático V8 :: Handle Add (const v8 :: argumentos e args); estático V8 :: Handle ToString (const V8 :: Argumentos e Args);
onde o método tostring () nos permite obter o valor de S_ em vez do valor do [objeto objeto] ao usá -lo com uma string javascript normal.
Por fim, introduziremos o método de inicialização (este método será chamado pelo V8 e atribuído à função do construtor) e fechará a Guarda:
Public: estático void init (v8 :: manipular exportações); }; #endif
O papel do objeto de exportação no módulo JavaScript é equivalente ao módulo.Exports.
Arquivo STDSTRING.CC, Construtor e função de análise
Agora crie o arquivo stdstring.cc. Primeiro precisamos incluir nosso cabeçalho:
#include "stdstring.h"
A seguir, define a propriedade para o construtor (porque pertence a uma função estática):
v8 :: persistente stdstringwrapper :: construtor;
Este construtor que serve a classe atribuirá o atributo S_:
Stdstringwrapper :: stdstringwrapper (std :: strings s) {s_ = new std :: string (s); }E a função de análise excluirá para evitar o excesso de memória:
Stdstringwrapper :: ~ stdstringWrapper () {exclation s_; }Além disso, você deve excluir todo o conteúdo atribuído com o novo, porque toda vez que essa situação pode causar uma exceção, lembre -se das operações acima ou use um ponteiro compartilhado.
Método init
Este método será chamado pelo V8 e destina -se a inicializar nossa classe (atribua o construtor e coloque todo o conteúdo que pretendemos usar no JavaScript no objeto Exports):
Void StdstringWrapper :: init (v8 :: manipular exportações) {
Primeiro, precisamos criar um modelo de função para o nosso novo método:
v8 :: TPL local = v8 :: functionTemplate :: new (new);
Isso é um pouco semelhante à nova função no JavaScript - nos permite preparar nossas próprias classes JavaScript.
Agora podemos definir um nome para a função de acordo com as necessidades reais (se você perder esta etapa, o construtor estará em estado anônimo, ou seja, o nome é função somename () {} ou function () {}):
tpl-> setClassName (v8 :: string :: Newsymbol ("stdstring"));
Usamos o V8 :: String :: Newsymbol () para criar uma string de tipo especial para nomes de propriedades - que economiza um pouco de tempo para a operação do motor.
Depois disso, precisamos definir quantos campos nossa instância de classe contém:
tpl-> instancetemplate ()-> setInternalfieldCount (2);
Temos dois métodos - Add () e ToString (), então definimos o número para 2. Agora podemos adicionar nossos próprios métodos ao protótipo de função:
tpl-> prototyPeTemplate ()-> set (v8 :: string :: newsymbol ("add"), v8 :: functionTemplate :: new (add)-> getFunction ());
tpl-> prototypeTemplate ()-> set (v8 :: string :: Newsymbol ("tostring"), v8 :: functionTemplate :: new (tostring)-> getFunction ());
Essa parte do código parece bastante grande, mas, desde que você observe cuidadosamente, você encontrará as regras: usamos TPL-> prototyPeTemplate ()-> set () para adicionar cada método. Também usamos o V8 :: String :: Newsymbol () para fornecer a eles nomes e funçãoTemplate.
Finalmente, podemos colocar o construtor no objeto de exportação em nossas propriedades da classe construtora:
construtor = v8 :: persistente :: new (tpl-> getFunction ()); exports-> set (v8 :: string :: Newsymbol ("stdstring"), construtor); }Novo método
Agora, o que precisamos fazer é definir um método que funcione o mesmo que JavaScript Object.prototype.Constructor:
v8 :: Handle stdstringwrapper :: new (const v8 :: argumentos e args) {Primeiro precisamos criar um escopo para isso:
v8 :: Handlescope Scope;
Depois disso, podemos usar o método .isconstructCall () do objeto Args para verificar se o construtor pode ser chamado usando a nova palavra -chave:
if (args.isconstructCall ()) {Se puder, passamos primeiro o parâmetro para std :: string da seguinte forma:
v8 :: string :: utf8Value str (args [0]-> tostring ()); std :: string s (*str);
... para que possamos passar para o construtor de nossa classe encapsulada:
Stdstringwrapper* obj = new stdstringwrapper (s);
Depois disso, podemos usar o método .Wrap () do objeto que criamos anteriormente (herdado do Node :: ObjectWrap) para atribuí -lo a esta variável:
obj-> wrap (args.his ());
Finalmente, podemos devolver este objeto recém -criado:
retornar args.This ();
Se a função não puder ser chamada com a nova, também podemos chamar o construtor diretamente. Em seguida, o que queremos fazer é definir uma constante para a contagem de parâmetros:
} else {const int argc = 1;Agora precisamos criar uma matriz usando nossos próprios parâmetros:
v8 :: argv local [argc] = {args [0]};Em seguida, passe o resultado do método do construtor-> NewInstance para escopo.
Return scope.close (construtor-> newInstance (argc, argv)); }}
Adicionar método
Agora, vamos criar o método Add, que se destina a permitir que todos adicionem conteúdo ao std interno do objeto :: string:
v8 :: Handle stdstringwrapper :: add (const v8 :: argumentos e args) {Primeiro, precisamos criar um intervalo para nossa função e converter o parâmetro em STD :: string como antes:
v8 :: Handlescope Scope; v8 :: string :: utf8Value str (args [0]-> tostring ()); std :: string s (*str);
Agora precisamos descompactar o objeto. Também realizamos essa operação de encapsulamento reverso antes - desta vez, obteremos um ponteiro para o objeto dessa variável.
Stdstringwrapper* obj = objectWrap :: Unwrap (args.This ());
Em seguida, podemos acessar o atributo S_ e usar seu método .append ():
obj-> s _-> anexar (s);
Por fim, retornamos o valor atual do atributo S_ (precisamos usar o SCOPE.CLOSE novamente):
Return scope.close (v8 :: string :: new (obj-> s _-> c_str ()));
Como o método V8 :: string :: new () só pode aceitar o Pointer Char como um valor, precisamos usar obj-> s _-> c_str () para obtê-lo.
No momento, um diretório de compilação deve ser criado na pasta plug-in.
teste
Agora podemos testar nossos plug-ins. Crie um arquivo test.js e bibliotecas de compilação necessárias em nosso diretório plug-in (você pode pular diretamente a extensão .node):
var addon = requer ('./ build/release/addon');Em seguida, crie uma nova instância para o nosso objeto:
var teste = new addon.stdstring ('teste');Em seguida, faça -o, como adicioná -lo ou convertê -lo em uma string:
test.add ('!'); console.log ('Test/' S Conteúdo: %S ', teste);Após a execução, você deve ver os seguintes resultados de execução no console:
para concluir
Espero que, depois de ler este tutorial, você possa dissipar suas preocupações e considerar a criação e teste de plug-ins Node.js personalizados com base nas bibliotecas C/C ++ como uma tarefa muito difícil. Você pode usar esta tecnologia para introduzir facilmente quase qualquer biblioteca C/C ++ no Node.JS. Se você quiser, também pode adicionar mais funções ao plug-in de acordo com as necessidades reais. O STD :: String fornece muitos métodos e podemos usá -los como materiais de exercício.
Links práticos
Os amigos interessados podem verificar os seguintes links para obter mais recursos e detalhes relacionados ao desenvolvimento de plug-in node.js, bibliotecas de loop de eventos V8 e C.
• Documentação do plug -in Node.js
• Documentação V8
• Libuv (C Biblioteca de Loop de Eventos), do GitHub
Inglês: http://code.tutsplus.com/tutorials/writing-nodejs-addons-cms-21771