Allan Esquina

Front End Engineer

Trabalho no UOL, atualmente na área de infografia

allan.esquina@gmail.com

github.com/allanesquina

codepen.io/allanesquina

Trabalho a mais de 9 anos com web

MCTS - Web Applications Development with Microsoft .NET Framework 4

Programming in HTML5 with JavaScript and CSS3

php, c#, java, javascript

Sou fundador da organização

nofreakz.com

Ubuntu Pixel Perfect

Cornergrid

FreakNav

Sudotrap

PolygonJS

Fontes

http://nodebr.com/

imaster.com.br

Aplicacoes web real time com nodejs - Caio Ribeiro Pereira

Palestras

Emerson Macedo Leite

Giovanni Bassi

Luciano Ramalho

O que é Node JS?

Uma plataforma para trabalhar com aplicações de alta concorrência.

Aplicações escaláveis??

Ok, vamos rever alguns conceitos

Performance

Habilidade que uma aplicação tem de atingir um objetivo, como por exemplo responder no menor tempo possível.

Capacidade

A carga total que uma aplicação pode suportar.

Escalabilidade

A habilidade de uma aplicação manter a performance quando a carga de trabalho aumenta. É a junção da capacidade e da performance.

Performance

A velocidade do carro.

Capacidade

O limite de velocidade e o número de pistas da estrada.

Escalabilidade

Quantos carros e pistas eu posso adicionar sem diminuir a velocidade do tráfego.

Uma plataforma para facilitar o desenvolvimento de aplicações escaláveis.

Como?

Sync/Async

Arquitetura Bloqueante

Executa um processo por vez, gerando uma fila de processos.

Imagine que cada requisição no server seja um processo.

Se tivermos um número muito grande de requisições simultâneas, a fila de processos chegará ao seu limite, obrigando o servidor a dropar as requisições exedentes.

Código de status 503

O servidor está temporariamente indisponível.

Síncrono

Blocking-Thread

Arquitetura Não Bloqueante

O Oposto!

"Como assim? Explica ae po!"

Arquitetura do NodeJS

NodeJS é orientado a eventos

Possui um "Event Loop"

Loop Infinito que escuta e dispara eventos.

NodeJS é Single-Thread e trabalha com callbacks

Como assim?

O nodejs trabalha apenas com uma fila, porém, quando ele recebe uma requisição, ele dispara um processo e volta pra esperar por outra.

Desta forma, a aplicação não é bloqueada, podendo receber e processar outra requisição.

E como eu sei quando um processo termina?

Callback

Esta forma de trabalhar é Assíncrona.

Cluster

É possivel instanciar varios processos do nodejs em uma mesma porta, trabalhando de forma distribuída. O Ideal é este número ser relativo ao número de núcleos de CPU do servidor.

Instalação

Compilando o source


	sudo apt-get install python g++ make checkinstall
mkdir ~/src && cd $_
wget -N http://nodejs.org/dist/node-latest.tar.gz
tar xzvf node-latest.tar.gz && cd node-v*
./configure
checkinstall #(remove the "v" in front of the version number in the dialog)
sudo dpkg -i node_*
						

Advanced Packaging Tool

nodejs 0.6.x


					sudo apt-get install nodejs
						

Advanced Packaging Tool

Versão mais recente


					sudo apt-get update
sudo apt-get install python-software-properties python g++ make
sudo add-apt-repository ppa:chris-lea/node.js
sudo apt-get update
sudo apt-get install nodejs
						

Arch Linux


					pacman -S nodejs
						

Windows

Windows Installer (.msi)


							http://nodejs.org/download/
						

NPM

Node Packaged Modules

Gerenciando módulos


npm install nome_do_módulo (instala um módulo)
npm install -g nome_do_módulo (instala um módulo global.)
npm install nome_do_módulo --save (instala atualizando o package.json.)
npm list (lista todos os módulos do projeto.)
npm list -g (lista todos os módulos globais.)
npm remove nome_do_módulo (desinstala um módulo do projeto.)
npm remove -g nome_do_módulo (desinstala um módulo global.)
npm update nome_do_módulo (atualiza a versão do módulo.)
npm update -g nome_do_módulo (atualiza a versão do módulo global.)
npm -v (exibe a versão atual do npm.)
						

package.json

O que é?

Um arquivo que descreve um módulo


{
	"name": "nome-do-módulo",
	"description": "descrição do módulo",
	"author": "Allan Esquina",
	"version": "1.2.3",
	"private": true,
	"dependencies": {
		"modulo-1": "1.0.0",
		"modulo-2": "~1.0.0",
		"modulo-3": ">=1.0.0"
	},
	"devDependencies": {
		"modulo-4": "*"
	}
}
						

Entendendo Níveis de Versionamento

Major release(1), Minor release (2) e Patch (3)

Versão par Estável

Versão ímpar Instável

Entendendo as versões de dependências


{
	...

	"dependencies": {
		"modulo-1": "1.0.0", (Pega a versão 1.0.0, é fixo)
		"modulo-2": "~1.0.0",(Atualiza a nível de patch)
		"modulo-3": ">=1.0.0" (Versão igual ou superior a 1.0.0) 
	},
	
	"devDependencies": {
		"modulo-4": "*" (Sempre a última versão)
	}
}
						

Módulos

O nodejs usa o padrão CommonsJS para organizar seus módulos

Entendendo a fuñção require()

Prefixos ./ /

Os prefixos determinam a localização do módulo.

  • / utiliza o caminho absoluto do módulo
  • ./ utiliza o caminho relativo a partir do caminho atual.

Extensão dos módulos

  • .js: o arquivo é iterpretado como um arquivo de código fonte javascript;
  • .json: é utilizado um analisador JSON no arquivo;
  • .node: interpretado como um addon através do dlopen.

require("http") Carrega um módulo incluido no núcleo do nodejs

require("/nome-do-arquivo") carrega um arquivo colocando a extensão 
(.js|.json|.node) no path absoluto do sistema de arquivo

require("./nome-do-arquivo") carrega um arquivo no path relativo ao módulo 
que chamou o require
						

Módulos de node_modules

Quando o arquivo não é prefixado e não é nativo do Node core modules, o Node busca o módulo na pasta node_module.


require("modulo");
						

/home/nodeapps/project/node_modules/modulo.js
/home/nodeapps/node_modules/modulo.js
/home/node_modules/modulo.js
/node_modules/modulo.js
						

module.exports

operacoes.js


exports.soma = function (a,b) {
	var resultado = a + b;
	console.log(resultado);
};

exports.sub = function (a,b) {
	var resultado = a - b;
	console.log(resultado);
};
						

var obj = require("./operacoes");
obj.soma(1,9); // 10
obj.sub(1,9); // -8
						

Cache

Os módulos são salvos em cache no seu primeiro carregamento, logo, todas as chamadas retornarão o mesmo módulo.

Variávies do Escopo de um módulo

__filename

O nome do arquivo do código que está sendo executado

__dirname

O nome do diretório que está salvo o script que está sendo executado

process

Um objeto que é associado ao presente processo em execução. Além de variáveis, este objeto tem métodos como process.exit, process.cwd e process.uptime

global

Está acessível em qualquer parte da aplicação.


global.usuario = "Allan";
console.log(global.usuario);
						

Criando \o/ primeiro Server

Criando um server http

server1.js


var http = require('http'),

server = http.createServer(function(request, response){
  response.writeHead(200, {"Content-Type": "text/html"});
  response.write("

Hello World!

"); response.end(); }); server.listen(3000, function() { console.log("start server on port 3000"); });

Trabalhando com rotas


var http = require('http'),
	port = 3000;

var server = http.createServer(function(request, response){
		
		response.writeHead(200, {"Content-Type": "text/html"});
		
		if(request.url == "/"){
			response.write("

Index

"); }else if(request.url == "/user"){ response.write("

User

"); }else{ response.write("

Not found!

"); } response.end(); }); server.listen(port, function(){ console.log('start server on port ' + port); });

Lendo arquivos


var fs = require('fs');
...

fs.readFile(__dirname + '/index.html', function(err, data){
	...
});

...
					

Lendo arquivos no server


var http = require('http'),
	fs = require('fs'),
	port = 3000,
	server = http.createServer(function(request, response){
		
		fs.exists(__dirname + request.url, function(exists) {
			if(exists) {
				fs.readFile(__dirname + request.url, function(err, html){
					response.writeHeader(200, {'Content-Type': 'text/html'});
					response.write(html);
					response.end();
				});
			} else {
				response.writeHeader(200, {'Content-Type': 'text/html'});				
				response.end("

404

"); } }); }); server.listen(port, function(){ console.log('start server on port ' + port); });

Express

O que é?

Framework MVC criado para facilitar o trabalho.

Semelhante ao Sinatra da linguagem Ruby

Algumas características

MVC (Model-View-Controller);

Roteamento de urls via callbacks

Middleware

Interface RESTFul

Suporte a File Uploads

Configuração baseado em variáveis de ambiente

Suporte a helpers dinâmicos

Integração com Template Engines

Integração com SQL e NoSQL

Instalando o express

CLI (Command Line Interface)


npm install -g express
						

Criando um projeto com express


express project-name --ejs
cd project-name
npm install
						

estrutura de pastas

public: pasta pública que armazena conteúdo estático.

routes: diretório que mantém todas as rotas da aplicação.

views: diretório que contém todas as views que são renderizadas pelas rotas.

express()

Retorna um objeto contendo todas as funcionalidades do framework

métodos do protocolo HTTP

app.get()

app.post()

app.put()

app.del()

Recebem 2 parametros

string referente a uma rota

função callback

Exemplo


app.get('/contatos', function(request, response) {
	console.log(...);
});

						

Convenção do Express


app.get('/', routes.index);
						

A chamada routes.index busca o arquivo index.js que contenha a função exports.index

bodyParser()

Trás um objeto com chave e valor dos dados enviados.

logger()

Biblioteca para trabalhar com logs

methodOverride()

Permite utilizar o mesmo path entre métodos HTTP

Exemplo de methodOverride()


app.get('/contatos', contatos.index);
app.get('/contato/:id', contatos.show);
app.post('/contato', contatos.create);
app.get('/contato/:id/editar', contatos.edit);
app.put('/contato/:id', contatos.update);
app.del('/contato/:id', contatos.destroy);
						

express.static

Define um diretório para servir arquivos estáticos.

Session


app.use(express.cookieParser());
app.use(express.session({secret: '1234567890NOFREAKZ'}));
						

Exemplo de Session


exports.index = function(req, res){
	req.session.nome = "Allan";
	res.render('index', { title: 'Express' });
};
						

exports.list = function(req, res){
  res.send("respond with a resource " + req.session.nome);
};
						

EJS

Embedded JS

Ativando EJS no express


app.set('view engine', 'ejs');
						

Renderizando uma view


exports.index = function(req, res){
  res.render('index', { title: 'Remote Control' });
};
						

Entendendo um template


						<!DOCTYPE html>
<html>
  <head>
    <title><%= title %></title>
    <link rel='stylesheet' href='/stylesheets/style.css' />
  </head>
  <body>
    <h1><%= title %></h1>
    <p>Welcome to <%= title %></p>
  </body>
</html>
					

Tool

Node Supervisor

Instalação


npm install supervisor -g
						

Utilização


supervisor program.js
						

Node Inspector

Instalação


npm install -g node-inspector
						

Utilização


node --debug your/node/program.js
node-inspector &
						

socket.io

Conecta o cliente ao servidor em tempo real

Transportes Suportados

WebSocket

Adobe® Flash® Socket

AJAX long polling

AJAX multipart streaming

Forever Iframe

JSONP Polling

Navegadores Suportados

Desktop

Internet Explorer 5.5+

Safari 3+

Google Chrome 4+

Firefox 3+

Opera 10.61+

Mobile

iPhone Safari

iPad Safari

Android WebKit

WebOs WebKit

Instalando socket.io


npm install socket.io
						

Usando socket.io - Server


var app = require('http').createServer(handler)
  , io = require('socket.io').listen(app)
  , fs = require('fs')

app.listen(80);

function handler (req, res) {
  fs.readFile(__dirname + '/index.html',
  function (err, data) {
    if (err) {
      res.writeHead(500);
      return res.end('Error loading index.html');
    }

    res.writeHead(200);
    res.end(data);
  });
}

io.sockets.on('connection', function (socket) {
  socket.emit('news', { hello: 'world' });
  socket.on('my other event', function (data) {
    console.log(data);
  });
});
						

Usando socket.io - Cliente


<script src="/socket.io/socket.io.js"></script>
<script>
  var socket = io.connect('http://localhost');
  socket.on('news', function (data) {
    console.log(data);
    socket.emit('my other event', { my: 'data' });
  });
</script>
						

Usando socket.io com Express - server


var app = require('express')()
  , server = require('http').createServer(app)
  , io = require('socket.io').listen(server);

server.listen(80);

app.get('/', function (req, res) {
  res.sendfile(__dirname + '/index.html');
});

io.sockets.on('connection', function (socket) {
  socket.emit('news', { hello: 'world' });
  socket.on('my other event', function (data) {
    console.log(data);
  });
});
						

Usando socket.io com Express - cliente


<script src="/socket.io/socket.io.js"></script>
<script>
  var socket = io.connect('http://localhost');
  socket.on('news', function (data) {
    console.log(data);
    socket.emit('my other event', { my: 'data' });
  });
</script>

						

Espera uma conexão com um cliente, retorna um objeto socket do cliente conectado


io.sockets.on('connection', function (socket) {
  socket.emit('news', { hello: 'world' });
  socket.on('my other event', function (data) {
    console.log(data);
  });
});
						

Disparando evento para todas as conexões


io.sockets.emit("event", data);
						

Testes (TDD)

Nodeunit

Mocha

qUnit

Expresso

Sites bacanas

nitrous.io

c9.io

jsapp.us

nodejitsu.com

heroku.com

nodecloud.org

Obrigado!