As vezes é bastante difícil aprender uma linguagem de programação, principalmente por não sabermos por onde começar. Vamos lá!

O Node.js nada mais é do que JavaScript executado no servidor, e isso é muito bom por diversos motivos. Mas, antes de codar, é importante entender alguns conceitos chave e um pouco de história.

É muito importante também, entender que o Node.js não é uma solução mágica, nem sempre sendo a melhor solução para todos os projetos ou problemas. Qualquer um pode iniciar um servidor no Node.js, mas é necessário entendimento mais profundo da linguagem para escrever aplicações web escaláveis.

Antes do Node.js

Senta que vem história...

As aplicações web, em sua maioria, foram escritas em um modelo servidor/cliente, onde o cliente exige um recurso do servidor, que por sua vez responde com os recursos solicitados. Assim, o servidor só responde quando o cliente solicita e fecha a conexão após cada resposta.

Esse padrão é eficiente já que cada solicitação ao servidor consome tempo e recursos (CPU, memória, rede, etc.). Assim, é mais sensato fechar a conexão após o servidor responder a solicitação para que seja possível também responder as próximas requisições.

Então, pensando nessa arquitetura, como um servidor responde a centenas ou milhares de requisições ao mesmo tempo? Pois bem, para isso existe algo chamado threads. Threads, em resumo, são uma forma dos sistemas executarem várias operações simultaneamente. Portanto, cada solicitação abre um novo encadeamento, cada encadeamento possui tudo o que é necessário para executar uma operação até a sua conclusão.

Esse sistema de threads tem uma desvantagem (ou mais...), chegará o momento em que haverá muitas solicitações e o aumento de threads filhas acabará por consumir uma grande quantidade de recursos (memória, CPU, etc). Isso poderá causar uma lentidão nas requisições. Uma vez que cada nova solicitação é tratada por um novo encadeamento, é preciso um trabalho bastante eficiente da thread principal, tornando o sistema mais rápido e capaz de atender solicitações mais rapidamente.

Isso tudo é bastante eficiente por que cada operação executa o código fora da thread principal. Mas as coisas sempre podem ser melhores não é?

Aí vem o Node.js

Imagine um servidor multi-thread rodando Ruby on Rails - a versão anterior do meu site era em Ruby :). Nele há a operação de ler um arquivo salvo no servidor e responder com os dados para a solicitação. O Ruby por sua vez, não lê arquivos diretamente, ele depende do file system realizar essa operação. Então, é feita a solicitação para o file system e enquanto isso o Ruby fica com uma thread aguardando a resposta dele para, somente após, devolver a resposta para quem fez a solicitação.

É aí que o Node.js entra com toda sua sabedoria. Utilizando o mesmo exemplo anterior, enquanto o file system está lendo o arquivo, o Node.js usa o tempo ocioso para lidar com outras solicitações. Quando o file system concluir, ele irá notificar o Node.js para buscar as informações e devolver como resposta à solicitação. Isso é possível por causa do conhecido event loop.

O event loop é basicamente um programa que fica esperando por eventos e os despacha quando acontecem. Um fato importante de citar aqui, é que JavaScript é single thread e portanto Node.js também.

Ao contrário de outras linguagens que exigem um novo thread para cada solicitação, o Node.js pega todas as solicitações e delega a maior parte do trabalho para outros workers do sistema. Assim que esses workers em segundo plano terminam seu trabalho, emitem eventos de callback registrados nesse evento.

Outro item importante, callbacks! Eles são basicamente funções passadas para outras funções como argumentos e são chamados quando ocorrem certas condições.

Portanto, o que programadores em Node.js fazem basicamente é escrever manipuladores de eventos.

Mas, o Node.js é mais rápido que outros sistemas multi-threads? Sim, mesmo sendo single-thread.

Também é muito importante saber que tudo em JavaScript é executado em paralelo, exceto seu código. Sim, seu código executa uma coisa por vez, mesmo quando outros workers estão fazendo seu trabalho simultaneamente. Calma, vamos fazer uma analogia caso não tenha entendido 100%.

Imagine que o presidente da república tem um assessor. O presidente escreve uma lista de coisas que deseja que sejam feitas e a envia para seu assessor, que por sua vez delega o trabalho a vários outros funcionários. Quando terminar, o assessor leva os resultados ao presidente. O presidente está sempre ocupado escrevendo outras listas enquanto o assessor e os funcionários estavam trabalhando.

Nesta analogia, o presidente é seu código. Mesmo que muitas coisas estejam correndo em paralelo, ele faz uma coisa de cada vez. Seus funcionários são os workers do Node.Js. "Tudo é executado em paralelo, exceto o seu código" – Mikito Takada.

Conclusão

Ufa! Acho que ficou um pouco extenso, por isso vamos parando por aqui nesse primeiro artigo.

Se você quer escrever aplicações escaláveis com Node.Js, você precisa saber mais do que apenas escrever código e rotear com express. É importante conhecer como funciona, por trás do código. Os próximos passos serão conhecer conceitos como síncrono/assíncrono, promises, callbacks, entre outros. Mas vamos por partes! ;)

Ficou com dúvida? Gostou das analogias? Comenta aí e vamos trocar uma ideia!