Tempo de leitura: 9 minutos
Deseja compreender o que é Node.js e como funciona sua estrutura?
Se você já vem estudando, pesquisando ou trabalhando com tecnologias, com certeza já deve ter ouvido muito falar de Node.Js que hoje é considerada uma das tecnologias mais leves e poderosas do mercado.
O Node.js surgiu quando os criadores originais do JavaScript pensaram além e viram no JavaScript padrão (que só podia ser executado no navegador) uma oportunidade e o transformaram em algo que pudesse ser executado em sua máquina como um aplicativo independente.
Quer entender o que é Node.js e tudo que essa tecnologia é capaz de fazer? Fica comigo nesse artigo pois nós da Danki Code vamos te mostrar todos os detalhes.
O que você irá aprender neste artigo?
// Como funcionam as aplicações do Node.js?
O que é Node.Js
Node.js® é um runtime JavaScript desenvolvido com o Chrome’s V8 JavaScript engine.
O ambiente Node.js inclui tudo o que você precisa para executar uma aplicação escrita em JavaScript.
Portanto, agora você pode fazer muito mais, e não só apenas tornar seus websites mais interativos.
O JavaScript agora tem poder de realizar coisas que outras linguagens de script, como o Python, podem fazer.
O JavaScript do seu navegador e o Node.js são executados na engine V8 JavaScript como citado acima.
Este mecanismo pega seu código JavaScript e o converte em um código de máquina bem mais veloz.
O código da máquina é um código de baixo nível que o computador pode executar sem precisar interpretá-lo primeiro.
Por que o Node.js?
Agora vamos entender de fato por que o Node.js é tão popular.
O Node.js estabeleceu o seu objetivo primordial, que é fornecer uma maneira mais simples de construir programas de rede escaláveis.
Que problemas existem com os programas servidores atuais?
Vamos calcular. Em linguagens como PHP e Java™, cada conexão estabelecida cria uma thread nova que potencialmente tem anexado 2 MB de memória com ela.
Em um sistema que possui 8 GB de RAM, isso põe o número máximo teórico de conexões concorrentes a cerca de 4.000 usuários.
E quando aumenta o número de usuários, se você deseja que sua aplicação web suporte mais usuários, você irá ter que adicionar mais e mais servidores.
Além do mais você pode ter possíveis problemas técnicos: um usuário pode usar servidores diferentes para cada requisição, então cada recurso compartilhado deve ser compartilhado para todos os servidores.
Por estas razões que foram apresentadas o grande gargalo existente em toda a arquitetura de aplicações web (incluindo velocidade de tráfego, velocidade do processador e velocidade da memória) é o número de conexões concorrentes que o servidor pode manipular.
Como o Node.js resolve essa questão?
Ele resolve esta problemática modificando a forma como a conexão é tratada no servidor.
Ao invés de criar uma nova OS thread a cada conexão (e alocar a memória anexa a ela), cada conexão dispara um evento executado dentro da engine de processos do Node.
O Node afirma que nunca vai dar deadlock, já que não há bloqueios permitidos, e ele não bloqueia diretamente para chamadas de I/O.
O Node.js também defende que um servidor executando ele pode suportar milhares e milhares de conexões simultâneas.
O Node.js usa um modelo de I/O sem bloqueio orientado a eventos que o torna leve e eficiente.
O ecossistema de pacotes do Node.js, npm, é o maior ecossistema de bibliotecas de código aberto no mundo.
Vamos entender o funcionamento destes modelos.
I/O refere-se a entrada/saída.
Pode ser qualquer coisa, desde ler/gravar arquivos locais até fazer uma solicitação HTTP para uma API.
I/O leva tempo e, portanto, bloqueia outras funções.
Considere um cenário em que solicitamos um banco de dados back-end para os detalhes de usuario1 e usuario2 e, em seguida, imprimi-los na tela/console.
A resposta a essa solicitação leva tempo, mas ambas as solicitações de dados do usuário podem ser executadas de forma independente e de forma simultânea.
E/S de bloqueio (esquerda) vs E/S sem bloqueio (direita)
Bloqueio de I/O
No método de bloqueio, a solicitação de dados do usuario2 não é iniciada até que os dados do usuario1 sejam impressos na tela.
Se este fosse um servidor web, teríamos que iniciar um novo thread para cada novo usuário. Mas o JavaScript é single-threaded.
Então isso tornaria o JavaScript não muito adequado para tarefas multi-threaded.
É aí que entra a parte sem bloqueio.
I/O sem bloqueio
Por outro lado, utilizando uma solicitação sem bloqueio, você pode fazer uma solicitação de dados para o usuário2 sem esperar pela resposta da solicitação do usuário1. Você pode iniciar as duas solicitações em paralelo.
Essa I/O sem bloqueio elimina a necessidade de multiencadeamento, pois o servidor pode manipular inúmeras solicitações ao mesmo tempo.
Node.js Event Loop
O Node.js é um aplicativo de encadeamento único, mas pode suportar a simultaneidade por meio do conceito de evento e retornos de chamada.
Cada API do Node.js é assíncrona e com um único encadeamento, eles usam chamadas de função assíncronas para manter a simultaneidade.
O Node usa o padrão de observador. O encadeamento de nós mantém um loop de eventos e, sempre que uma tarefa é concluída, ele dispara o evento correspondente, que sinaliza a execução da função event-listener.
Programação orientada a eventos
O Node.js utiliza os eventos de forma muito poderosa e essa é também uma das razões pelas quais o Node.js é bastante rápido em comparação com outras tecnologias semelhantes.
Assim que o Node inicia seu servidor, ele simplesmente inicia suas variáveis, declara funções e simplesmente espera que o evento ocorra.
Em um aplicativo orientado a eventos, geralmente há um loop principal que ouve eventos e dispara uma função de retorno de chamada quando um desses eventos é detectado.
Embora os eventos pareçam bastante semelhantes aos retornos de chamada, a diferença está no fato de que as funções de retorno de chamada são chamadas quando uma função assíncrona retorna seu resultado, enquanto a manipulação de eventos funciona no padrão do observador.
As funções que escutam eventos agem como Observadores.
Sempre que um evento é disparado, sua função de ouvinte começa a ser executada.
O Node.js tem vários eventos incorporados disponíveis por meio do módulo de eventos e da classe EventEmitter, que são usados para vincular eventos e ouvintes de eventos da seguinte maneira:
// Import events module var events = require('events'); // Create an eventEmitter object var eventEmitter = new events.EventEmitter();
A seguir, a sintaxe para vincular um manipulador de eventos a um evento –
// Bind event and event handler as follows eventEmitter.on('eventName', eventHandler);
Podemos disparar um evento programaticamente da seguinte maneira –
// Fire an event eventEmitter.emit('eventName');
Exemplo
Crie um arquivo js chamado main.js com o seguinte código –
// Import events module var events = require('events'); // Create an eventEmitter object var eventEmitter = new events.EventEmitter(); // Create an event handler as follows var connectHandler = function connected() { console.log('connection succesful.'); // Fire the data_received event eventEmitter.emit('data_received'); } // Bind the connection event with the handler eventEmitter.on('connection', connectHandler); // Bind the data_received event with the anonymous function eventEmitter.on('data_received', function() { console.log('data received succesfully.'); }); // Fire the connection event eventEmitter.emit('connection'); console.log("Program Ended.");
Agora vamos tentar executar o programa acima e verificar sua saída –
$ node main.js
TI deve produzir o seguinte resultado –
connection successful. data received successfully. Program Ended.
Como funcionam as aplicações do Node?
Na sua aplicação Node, qualquer função assíncrona aceita um retorno de chamada como o último parâmetro e uma função de retorno de chamada aceita um erro como o primeiro parâmetro.
Vamos revisitar o exemplo anterior novamente. Crie um arquivo de texto chamado input.txt com o seguinte conteúdo:
A Danki Code está oferecendo conteúdo de valor para você aprender de forma rápida e eficaz.
Crie um arquivo js chamado main.js com o seguinte código –
var fs = require("fs"); fs.readFile('input.txt', function (err, data) { if (err) { console.log(err.stack); return; } console.log(data.toString()); }); console.log("Program Ended");
Aqui fs.readFile () é uma função assíncrona cuja finalidade é ler um arquivo.
Se ocorrer um erro durante a operação de leitura, o objeto err irá conter o erro correspondente, senão os dados conterão o conteúdo do arquivo. readFile passa err e dados para a função de retorno de chamada após a conclusão da operação de leitura, que finalmente imprime o conteúdo.
Conclusão
Gostou do artigo? Espero que com esse artigo você avance mais e mais nos seus estudos com Node.js, que é uma tecnologia cada vez mais crescente e já é utilizada por programadores do mundo inteiro, além de várias gigantes do mercado.
Aqui na Danki Code utilizamos o Node.js para fazer gerenciamento e consumir dependências feitas em JavaScript, para o desenvolvimento de novas interfaces para o usuário.
Em nosso e-book sobre FullStack vemos com mais detalhes sobre o Node.Js e muitas outras aplicações do universo fullStack, clique aqui e conheça mais profundamente o pacote Full Stack mais completo do Brasil.
Link permanente