Primeiro contato com Node.j e mais sobre non-blocking servers
Autor: Alexandre Simundi | Publicado: 2011-07-22T19:20:00-03:00






Dae gurizada..



Na sequência do meus estudos sobre non-blocking web servers vou dar uma olhada no Node.js.



Instalação:&nbsp;https://github.com/joyent/node/wiki/Installation



Vou utilizar como base esta apresentação do Ryan Dahl, que está disponível no site do node.js


Antes de olhar sobre Node.js é importante entender o C10K Problem e Non-blocking I/O


Node.js

Node.js nada mais é que uma biblioteca que roda em cima do virutal machine chamada&nbsp;v8.&nbsp;V8 é uma JavaScript Engine escrita pelos &nbsp;engenheiros da Google e é utilizada no Google Chrome.



Node utiliza o v8 para fazer o trabalho de comunicação (networking) corretamente.&nbsp;



Não existe "waiting time"

Óbvio, é isso que faze dele um non-blocking server: Não ter "waiting time".



Você não consegue mandar o node dormir (sleep). Não é que você seja encorajado a não fazer um "sleep", na verdade você não tem poder para isso.&nbsp;



O que o Node faz é definir Timeouts e deixar processos em idle (ocioso), fazendo com que o consumo de CPU vá para zero.




De uma olhada nesse código:



&nbsp;setTimeout( function(){
&nbsp; &nbsp; console.log("world");
&nbsp; &nbsp;}, 2000
&nbsp;)

&nbsp;console.log("hello");



A função timeout do java script está recebendo dois argumentos:

Uma função callback que será executada depois do tempo de espera
o tempo de espera em milisegundos

//output
hello
world

O que acontece aqui é que o programa não para quando chamo "setTimeout". &nbsp;O programa segue o o código que está dento da função passada para o "setTime" fica em idle e espera 2 segundos para ser executado.

Node nunca pára!

O script não termina quando chega ao fim

Mudei o código e chamei a função setInterval() ao invés da setTimeout(). Essa função executa a função recebida como parâmetro infinitamente a cada X milesegundos, definido no segundo argumento.

&nbsp;setInterval( function(){
&nbsp; &nbsp; console.log("world");
&nbsp; &nbsp;}, 2000
&nbsp;)

&nbsp;console.log("hello");
O resultado foi:

hello
world
world
world
world
world
world



Note que o script chegou ao fim, ou seja, executou a última linha de comando. Mas o programa continou sendo executando devido a chamada da função &nbsp;setInterval().

O lado bom disso é que você pode escrever tudo que precisa ser feito e não precisa se preocupar como manter o processo ativo.

Um ctrl + C resolve a parada.

Simples web server

Abaixo está um exemplo de como criar um servidor http. Esse é o mesmo código que está no site do Node.

var http = require('http');

var server = http.createServer(
&nbsp; function(request, response){
&nbsp; &nbsp; &nbsp;response.writeHead(200, {'content-type':'text/plain'});
&nbsp; &nbsp; &nbsp;response.end("Hello Wrold\n");
&nbsp; } 
);

server.listen(8080);
console.log("Server running at http://localhost: 8080");



A primeira linha carrega o pacote http. Depois disso criamos o serviço e definos a função que irá tratar cada requisição ao servidor.

Para iniciar o servidor basta digitar "node test3-httpServer.js" e &nbsp;será iniciado.

Fiz uma requisição utilizando o comando "curl" com o parâmetro "-i" para retornar o cabeçalho HTTP. 

simundi@simundi ~ $ curl -i http://localhost:8080
HTTP/1.1 200 OK
content-type: text/plain
Connection: keep-alive
Transfer-Encoding: chunked

Hello Wrold



Analisando o cabeçalho temos:


Versão 1.1: &nbsp;a última versãõ HTTP
Código 200: significa que a requisção foi bem sucedida.
Connection keep-alive: vai fazer com que a conexão TCP não seja enerrada logo após a reposta. O que é bom. Afinal, criar conexão TCP toda hora é um custo desnecessário.
Transfer-encoding Chunked: esse vale a pena explicar bem


Transfer-encoding: Chunked / Resposta Assíncrona

Antes de entender este atributo, vamos ver como as coisas funcionam sem ele. Um dos atributos existentes no cabeçalho HTTP é o Content-lenght, que diz o tamnho da reposta que está chegando do servidor. Dessa forma o browser(ou outro cliente) sabe quando a reposta terminou de ser enviada.



Reposta com Content-Length in the header.


Com o "Transfer-enconding" definido como "Chunked"&nbsp;NÃO TEM Content-Length. Ou seja, para o browser a resposta vai continuar chegando para sempre, até que o servidor informe que a resposta acabou.




Enviando a resposta é enviada em "prestações"


Agora vou mostar um exemplo disso no node.

var http = require('http')

var server = http.createServer(
&nbsp; function(request, response){
&nbsp; &nbsp; &nbsp;response.writeHead(200, {'content-type':'text/plain'});
&nbsp; &nbsp; &nbsp;response.write("Hello world\n")
&nbsp; &nbsp; &nbsp;setTimeout( function() {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;response.end("Second answer\n")
&nbsp; &nbsp; &nbsp;},2000 );

&nbsp; &nbsp; response.write("end of the script\n")

&nbsp; } 
);

server.listen(8080);
console.log("Server running at http://localhost: 8080");


Output:
Hello world
end of the script
later response

Nesse exemplo o programa escreve "hello world" e "end of script" direto. Depois de 2 segundos ele escreve "later response". &nbsp;Note que é código "response.end" que informa ao cliente que a resposta acabou. Isso é o que o "Transfer-Coding:&nbsp;Chunked" faz.


Outra coisa importante que de se notar é que entre a resposta "end of the script" e "later response" o servidor não parou. Ele continua rodando e disponível para receber novas requisições.

Código dos exemplos:&nbsp;https://github.com/simundi/gyro/tree/master/lab/nodejs


Por hoje é só. Node tem várias outras funcionalidades, mas estas vão ficar para outra hora.