Breno Ferreira

Opniões e códigos de um desenvolvedor de software .NET.

Primeiros passos com NodeJS

leave a comment »

Olá pessoal.

Hoje irei falar sobre um assunto um pouco diferente do que costumo escrever por aqui. Não é um assunto relacionado (nem tanto) ao mundo Microsoft. Irei falar hoje sobre uma tecnologia que tem gerado um “buzz” bem grande recentemente e que vem chamando a atenção de muitos desenvolvedores. Trata-se de Node.JS, ou simplesmente Node.

O que é Node.JS

Node.js is a platform built on Chrome’s JavaScript runtime for easily building fast, scalable network applications. (Fonte: http://nodejs.org/).

Duas coisas na descrição chamam a atenção:

Built on Chrome’s JS Engine (V8): Node permite que aplicações que rodem no server-side sejam construidas utilizando como linguagem o Javascript. Isso mesmo, Javascript. Isso é possível por que o Node interpreta seu código utilizando a engine de Javascript criada pelo Google, o V8. Talvez voce pense que Javascript é uma linguagem exclusiva para o mundo client-side, rodando em páginas web dentro do browser, mas com Node, suas habilidades adquiridas escrevendo código no lado do cliente poderão ser usadas no lado do servidor (a não ser que a única coisa que voce faz é amarrar eventos e Ajax simples via Jquery).

Fast e Scalable: A fundamental diferença entre Node e outros web-frameworks (além da linguagem, é claro), é que Node utiliza uma outra forma de tratar requests que chegam ao servidor. Frameworks como RubyOnRails, ASP.NET MVC, PHP (Zend, Cake, etc.), Django e outros, rodam sobre um WebServer, como Apache ou o IIS. E esses webservers utilizam Threads para tratar os requests. Então, para cada request que chega, o servidor aloca uma Thread (geralmente de uma ThreadPool) para tratar aquele request. Enquanto o processamento daquele request não terminar, aquela Thread fica “travada”, não podendo responder a outros requests. Por exemplo, muitas aplicações web implementam o que chamamos de Request-Database-Response, ou seja, um request chega, procuramos alguma informação no banco de dados e retornamos uma resposta pro cliente. Porém, o gargalo dessa execução está justamente na espera pelo banco de dados responder com as informações requeridas. Enquanto o BD não retorna, a Thread alocada ficará travada.

O Node por sua vez, utiliza um outra maneira de tratar requisições. Ele utiliza um recurso chamado Evented IO, que não faz uso de Threads, mas sim de uma pilha de eventos que são executados. Isso funciona da seguinte maneira: quando uma requisição chega ao servidor, o framework começa a tratar a requisição. A partir do momento que alguma operação de IO (seja para fazer alguma query no banco de dados, ler um arquivo, etc.) é executada, ela é executada de maneira assíncrona, e um evento (ou callback) é registrado. Enquanto essa operação de IO está executando, o processo do Node volta a ser capaz de continuar tratando outras requisições, resultando no que chamamos de Non-Blocking-IO. Quando a operação de IO anterior terminar, o callback registrado é colocado na pilha de execução e quando chegar sua vez, ele será executado, continuando a execução do request anterior, podendo assim, devolver uma resposta para o cliente. Em código, seria algo parecido com isso:

function EventLoop(){
	while (true){
		var callback = executionStack.Pop();
		callback();
	}
}

//called whenever an async IO operation is performed
function PushToExecutionStack(callback){
	executionStack.Push(callback);
}

Esse é o ingrediente fundamental que possibilita que aplicações escritas com Node sejam rápidas e escaláveis. Como o servidor nunca fica bloqueado esperando uma requisição terminar, ele pode servir milhares de requisições.

Mas por que Javascript?

Javascript é uma das poucas linguagens que, naturalmente, não oferece um modelo de programação síncrono. O conceito de callback é algo tão natural em Javascript, e todos estão tão acostumados a esse modelo de programação (ninguém faz AJAX de maneira síncrona, certo?) com essa linguagem, que Javascript é uma linguagem muito apropriada a esse modelo de programação orientado a eventos.

Exemplo

Abaixo temos um exemplo que cria um servidor que escuta na porta 8080 e que quando uma requisição chega, retorna o conteúdo do arquivo index.html.

var http = require('http');
var fileSystem = require('fs');

var server = http.createServer(function(req, resp){
	fileSystem.readFile('./index.html', function(error, fileContent){
		if(error){
			resp.writeHead(500, {'Content-Type': 'text/plain'});
			resp.end('Error');
		}
		else{
			resp.writeHead(200, {'Content-Type': 'text/html'});
			resp.write(fileContent);
			resp.end();
		}
	});
});

server.listen(8080);

console.log('Listening at: localhost:8080');

Primeiramente, chamamos a função require(‘http’) que carrega o módulo HTTP do Node. Com esse módulo, podemos chamar a função createServer, que recebe como parâmetro um callback, que será chamado toda vez que um request chegar para ser executado. A função de callback tem dois parâmetros, request e response. O parâmetro request possui os dados sobre o request, como headers, querystrings, content, etc.. O parâmetro response pode ser usado para enviar uma resposta para o cliente.

Na função responsável por tratar os requests, utilizamos a API do FileSystem para lermos o conteúdo do arquivo index.html, e novamente, passamos um callback que será chamado quando a leitura do arquivo terminar, e esse callback será chamado, devolvendo o conteúdo do arquivo, ou um erro, caso algum tenha ocorrido. Enfim, retornaremos uma resposta ao cliente, seja ela uma mensagem de erro, ou o conteúdo do arquivo. Fazemos isso chamando o método writeHead e write do objeto response. O método writeHead escreve um Header, nesse caso, passamos o Status-Code de 200 ou 500 e Content-Type sendo text/plain. O método write escreve o conteúdo da resposta, nesse caso o conteúdo do arquivo index.html

Note que, enquanto a leitura do arquivo está sendo feita, o processo do Node é capaz de continuar tratando outras requisições que chegarem.

Para executar essa aplicação, salve o código com algum nome, por exemplo “server.js”, e rode o seguinte comando no Terminal: node server.js. O código completo voce pode ver aqui. Não esqueça de criar o arquivo index.html com algum HTML de exemplo.

Era isso pessoal, até a próxima.

Breno

Written by Breno Ferreira

27/02/2012 at 14:00

Posted in Node.JS

Tagged with ,

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s