Prévia do material em texto
Node.js
Uma nova abordagem
da linguagem Javascript
De estudante para estudante
Material do grupo SoftwareOriginSP
2016
Fundado do grupo SoftwareOriginSP: Guilherme Guerra
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 2
O grupo SoftwareOriginSP, é um grupo independente fundado no
fim do ano de 2015, sem iniciativa do gorvenamental. Seu principal interesse é seguimenta da
criação de jogos para diversas plataformas tanto desktop ou móbile. Entretanto, adquirimos
alguns conceitos fundamentais que são estabelecidos para fazer ferramentas para as pessoas,
entre elas são: ferramentas para web, sendo sites dinâmicos, e entre outras que podam
contribuir na comunicação e da evolução do aspecto humano.
As tecnologias feitas pelo grupo são de alta telecomunição, para que as pessoas possam se
comunicar em qualquer lugar e a qualquer momento. Usamos ferramentas totalmente aceitas
no mercado tecnológico.
Contatos do grupo:
E-mail: guilhermeguerra96@outlook.com
G-mail: guilhermeguerra96@gmail.com
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 3
Telefone: (11) 2037-1232
1° Capítulo
Instalando e cofigurando o Node.Js
no ambiente Windows
Sobre o node.js
O node.js nasceu em meados de 2009 sendo o seu criador Ryan Dahl e uma equipe de 14
desenvolvedores que pretendiam criar uma plataforma para facilitar a criação de aplicações
real-time e de alta escalabilidade.
O objetivo principal do node.js é "fornecer uma maneira fácil de criar programas de rede
escaláveis" solucionando o principal problema das aplicações atuais feitas em Java, PHP ou
.NET, pois essas aplicações iniciam um processo para cada conexão que é acompanhado de
aproximadamente de 2MB de memória, desta forma limitando o número de acessos pela
quantidade de memória da máquina. Para contornar este problema são criados vários
servidores para tornar a aplicação mais escalável. O node.js veio para solucionar este
problema mudando a forma que é feito as conexões no servidor, pois ao invés de iniciar um
encadeamento em cada conexão será criado um processo que não necessita que o bloco de
memória fique alocado a este processo.
Algumas característica do node.js
Threads não bloqueantes: uma das melhores características do node.js onde não há um
controle de concorrências entre os recursos disponíveis para os processos. Nas linguagens
tradicionais como JAVA e .NET gerenciam as suas threads colocando em fila de execução onde
os processos que necessitam utilizar o mesmo recurso esperam a sua vez par usufruir do
recurso.
Programação Orientada à eventos I\O: existem diversas bibliotecas para se trabalhar com os
protocolos HTTP, HTTPS, Web Sockets (para aplicações real-time), entre outros protocolos.
Mecanismo V8: node.js roda Javascript no lado do servidor utilizando o mecanismo V8
(mecanismo Javascript do Google utilizado no Chrome). Podendo utilizar todo o poder da
ECMAScript5
Módulos: contém vários módulos para facilitar o desenvolvimento de aplicações como o
módulo de sockets, manipulação de arquivos, url, banco de dados NoSQL, entre outros.
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 4
Sobre o socket.io
O socket.io é um modulo do node.js que permiti fazer comunicação bidirecional utilizando
as APIs de transporte nativas dos browsers. Resumidamente este modulo que irá proporcionar
o real-time criando uma conexão com o servidor permitindo que haja a troca de informações
entre Client e Server sem a necessidade de solicitar um novo request.
A troca de informações entre Server e Client é feitas através de eventos onde cada ponta
deve monitorar um determinado evento que será disparado. Na parte de exemplos irei
detalhar com maiores informações como funciona o disparo dos eventos entre o Server e
Client.
Pré-requisitos
Executável do Node.js v.0.8.6 (Última versão se encontra no site.)
Python v.3.2.3 (Última versão se encontra no site.)
Servidor Web.
Estarei utilizando o WAMP como servidor Web local para demonstração do exemplo, caso
não tenha um servidor Web local e queira instalar o WAMP pode efetuar a instalação e
configuração utilizando este poste sobre Instalando e configurando o WAMP.
Instalando e configurando o node.js
A instalação do node.js no Windows 7 é muito tranquila, pois segue o padrão das
instalações for Windows os passos NNF (Next Next Finish) ou PPR (Próximo próximo e
reiniciar). Baixe o executável do node.js através do site oficial. A versão v0.8.6 se encontra do
site e poderá baixa e executa em direfentes versões do sistemas operacionais do Windows.
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 5
Após o download execute o aplicativo de instalação. Nesta instalação será instalado o
node.js, alguns módulos nativos e seu gerenciador de pacotes o NPM (Node Package
Manager). Este gerenciador servirá para a isntalação dos demais módulos para a utilização no
node.js como o nosso caso o socket.io. Vamos aos passos da instalação.
1º passo - Tela de instalação do node.js: esta tela informa sobre a instalação do node.js para
continuar clique no botão "Next"
2º passo - Licença de uso do node.js: nesta tela está descrito a licença do node.js para
instalação deve ser selecionado a opção "I accept the terms in the License Agreement" e clique
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 6
no botão "Next" caso apareça uma mensagem solicitando a confirmação da instalação
selecione a opção para continuar com o wizard.
3º passo - Conclusão da instalação do node.js: se tudo der certo a imagem abaixo deve ser
exibida assim confirmando a instalação do node.js. Clique no botão "Finish" para finalizar o
wizard.
4º passo - Permissão de acesso: O node.js será instalado no diretório padrão dos aplicativos
do Windows. No meu caso este será instalado em "C:\Program Files\nodejs". Precisamos dar
permissão para esta pasta para a instalação dos demais módulos do node.js no nosso caso o
socket.io. Para dar permissão a pasta vá no diretório de instalação do node.js e clique com o
botão direito do mouse na pasta "nodejs" e vá na opção "Propriedades":
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 7
Clique na aba "Segurança" no campo "Nome de grupos ou de usuários" você deverá dar
permissão ao Grupo de Usuários, então clique no botão "Editar" sendo exibida a tela conforme
imagem abaixo:
Selecione a opção "Usuários (NOME_DO_COMPUTADOR\Usuários)" e abaixo no campo
"Permissões para Usuários" clique na coluna "Permitir" no checkbox "Controle total" sendo
marcado o campo "Modificar" automaticamente. Clique botão "OK" retornando para a tela
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 8
das propriedades da pasta, clique novamente em "Ok" sendo fechado a tela o retornado para
a pasta de instalação do node.jsInstalando o Python
Quando necessitamos instalar algum módulo do node.js como o nosso caso o socket.io o
gerenciador de pacotes do Node.js (NPM) utiliza na versão Windows o Visual Studio ou o
Python, desta forma antes de instalar o módulo socket.io devemos instalar o Python. Baixe o
executável para a sua versão através deste link. Após o download execute o arquivo baixado
(python-3.2.3.msi).
1º passo - Permitindo execução: caso seja solicitado a execução deste aplicativo clique em
"Executar":
2º passo - Selecionando o tipo de instalação: nesta tela é informado se esta instalação será
para todos os usuários ou somente para o usuário que este instalando o aplicativo. Deixe a
opção "Install for all users" e clique em "Next":
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 9
3º passo - Selecionando diretório de instalação: neste passo você poderá informar um
diretório default para a instalação do Python, no meu caso deixarei o default "C:\Python32\".
Caso queira alterar escolha a sua pasta e clique no botão "Next" para prosseguir:
4º passo - Customizando a instalação: neste passo você poderá informar o que deseja ou não
na sua instalação. Em minha instalação deixei as opções como estão. Após a customização
clique em "Next":
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 10
5º passo - Finalizando a instalação: Neste ponto o sistema está instalando o aplicativo caso
seja informado uma mensagem para execução do aplicativo clique em "Sim". A tela de
finalização da instalação é exibida clique na opção "Finish" para finalizar a instalação.
Reiniciando o Windows
Este não é um passo que gostaria de estar colocando neste tutorial, mas em minhas últimas
três instalações tudo ocorreu corretamente só após reiniciar o Windows. Então antes de
continuar reinicie o seu SO para que as devidas configurações sejam efetivadas.
Instalando o socket.io
Com a instalação do node.js o seu gerenciador de pacotes (NPM) já está instalado e pronto
para ser usado assim podemos instalar os demais módulos para a utilização do node.js.
Por padrão as instalações dos módulos eu utilizo a mesma pasta onde efetuei a instalação do
node.js que no meu caso foi em "C:\Program Files\nodejs". Assim abra o prompt do
Windows (WinKey + R e digite cmd) e navegue até a pasta da sua instalação utilizando os
comandos: cd .. para voltar uma estrutura e cd NOME_DA_PASTA para acessar uma pasta. A
instalação do módulo será feita através do comando "npm install socket.io".
Vá no prompt e digite o comando acima e pressione ENTER, se tudo der certo deverá ser
informado a mensagem do sucesso da instalação.
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 11
Fique atento as mensagens que são exibidas no prompt, pois caso ocorra algum erro será
demonstrada uma mensagem.
Neste momento temos tudo que precisamos para utilizar o node.js com socket.io. Então
vamos aos exemplos para testarmos os aplicativos instalados.
Botando a mão na massa
Nesta parte do tutorial iremos ver através dos exemplos como podemos utilizar o node.js e
o socket.io. Os arquivos de exemplos serão executados pelo console (prompt do Windows)
utilizando o executável "node". Para demonstração irei salvar os arquivos de exemplos na
pasta de instalação do node.js que no meu caso está em "C:\Program Files\nodejs". Então
vamos os exemplos.
O famoso "Hello world": este exemplo que foi tirado do site oficial do node.js irá exibir o
texto "Hello word" no browser do usuário conectado no servidor, porém fiz algumas
alterações para demonstrar de uma forma mais detalhada o funcionamento de cada parte do
código. Crie um arquivo com o nome "hello_world.js" na pasta de instalação do node.js com o
conteúdo abaixo:
// Requisitando os módulos
var http = require('http');
/**
* Função que irá ser chamada a cada conexão com o Node.js
* @param {http.ServerRequest} req Instância do request da requisição
* @param {http.ServerResponse} resp Instância do response da requisição
*/
var onRequest = function (request, response) {
// Informando o tipo do cabeçalho da página
response.writeHead(200, {'Content-Type': 'text/plain'});
// Escrevendo um texto no response
response.write('Hello World\n');
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 12
// Encerrando o response
response.end();
};
// Criando o servidor informando a função de callback para o request
var server = http.createServer(onRequest);
// Iniciando o servidor na porta 1337
server.listen(1337, '127.0.0.1');
// Informando no console (prompt do Windows) a informação
console.log('Server running at http://127.0.0.1:1337/');
Com o arquivo criado abra o prompt do Windows e navegue até a pasta da instalação (ou a
pasta onde se encontra o arquivo). Digite o comando "node hello_world.js" e pressione
ENTER, se tudo der certo será exibido o texto no prompt "Server running at
http://127.0.0.1:1337/" conforme imagem abaixo:
Detalhando o código:
Linha #2: nesta linha é carregado o módulo HTTP do node.js utilizando o método require.
Este método irá retornar o Object referente ao módulo solicitado.
Linhas #9 a #18: criada a função que será executada a cada conexão no servidor. Esta
função irá receber dois parâmetros um sendo o request da conexão e outro o response da
requisição. Através do response podemos exibir as informações no browser do usuário.
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 13
Linha #11: nesta linha utilizando o método writeHead para informar o status code da página
(no nosso caso 200) e informando no segundo parâmetro o content type (tipo do conteúdo) da
página.
Linha #14: após informar qual será o content type da página será escrito o texto "Hello
world" utilizando o método write do Objeto response no browser do usuário.
Linha #17: o método end do Objeto response deve ser chamado em todo request. Caso
desejamos informar algo na página podemos informar no primeiro parâmetro o texto a ser
exibido. Seguindo o mesmo raciocínio do método write.
Linha #21: aqui que a mágica acontece. Nesta linha estamos criando o nosso servidor
utilizando o método createServer do módulo HTTP. Este método irá receber como parâmetro
uma função que será chamada (executada) no evento request do servidor, ou seja, em toda
requisição feita para o servidor.
Linha #24: com a referência do servidor criado podemos informar a porta que este irá
escutar, assim utilizando o método listen informo a porta de conexão e o hostname do
servidor.
Linha #27: uma forma de se debugar o código pelo console (prompt do Windows, Shell
Linux, etc) é utilizando a função console.log() onde esta deve receber como parâmetro o valor
a ser exibido no console. No nosso caso será somente exibida uma mensagem informando que
o servidor está rodando no hostname e porta informada no método listen.
Utilizando socket.io: irei demonstrar um exemplo simples, mas detalhado de como utilizar
o socket.io. Antes de demonstrar o exemplo gostaria de relembrar uma das características
informadas no início deste post, sobre "Programação Orientada à eventos I\O (POE)". Quando
estamos programando orientado a eventostemos que sempre estar pensando em callbacks,
ou seja, uma forma de interagir com o sistema quando um certo evento é disparado. Será
desta forma que iremos trabalhar com o socket.io.
"Então como funciona os eventos com o scoket.io?" Eventos serão disparados pelas duas
pontas da aplicação (Server side e Client side) através do socket que foi aberto. Nos dois lados
teremos um monitoramento (listeners) dos eventos que podem ser disparados.
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 14
Note pela imagem acima que o evento "userconected" é disparado pelo Client side
informando ao Server que o usuário foi conectado, desta forma temos no server um
monitoramento para este evento, onde através da função de callback será realizado uma
interação com o sistema. Da mesma forma o Server side emite o evento "showmessage" para
o Client, onde o socket deste possui um monitoramento do evento utilizando uma função de
callback que irá interagir com a aplicação.
Quem já programa algum tempo com Javascript esta familiarizado com este tipo de
programação, principalmente quem utiliza jQuery, ExtJS, Prototype, entre outros. Então vamos
ao nosso exemplo para demonstrar os conceitos informados acima.
1º Passo - Criando a estrutura no Server side: como no primeiro exemplo iremos criar um
arquivo na pasta de instação do node.js com o nome "socketio_exemplo.js" com o conteúdo
abaixo:
/**
* Função que irá ser chamada a cada conexão com o node.js
* @param {ServerRequest} request Instância do request da requisição
* @param {ServerResponse} response Instância do response da requisição
*/
var onRequest = function (request, response) {
// Informando o tipo do cabeçalho da página
response.writeHead(200, {'Content-Type': 'text/html'});
// Mensagem exibida no console há cada requisição
console.log('Usuário conectado no Server!!!');
// Encerrando o response
response.end();
};
// Requisitando os módulos
var http = require('http').createServer(onRequest),
io = require('socket.io').listen(http);
// Informando a porta para ser monitorada pelo Server
http.listen(8088, '127.0.0.1');
/**
* Evento "connection" que ocorre quando um usuário conecta no socket.io
* @param {SocketObject} socket Objeto do socket conectado
*/
io.sockets.on('connection', function(socket){
/**
* Evento "userconected" que ocorre quando a página é carregada.
*/
socket.on('userconected', function(){
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 15
// Enviando a mensagem só para o socket atual
socket.emit('showmessage', 'Usuário conectado no socket!!!');
// Servidor responde o mesmo resultado via broadcast.
socket.broadcast.emit('showmessage', 'Outro usuário foi conectado');
});
/**
* Evento "disconnect" emitido quando o usuário recarregar ou sair da página
*/
socket.on('disconnect', function(){
// Resposta do servidor via broadcast.
socket.broadcast.emit('showmessage', 'Um usuário saiu ou recarregou à página!!!');
});
});
Detalhando o código:
Linhas #6 a #15: é informado a função de callback que será chamada em toda requisição ao
node.js na porta 8088.
Linhas #18 e #19: são requisitados os dois módulos http e o socket.io. Sendo criado o
servidor do node.js utilizando a função "onRequest" e informando para o socket.io escutar a
conexão do módulo http.
Linha #22: informando para o servidor qual a porta e IP que este irá ser executado.
Linhas #28 e #47: este bloco será executado a toda conexão efetuada com o socket.io
através do Client. Note que informamos utilizando o método "on" o nome do evento a ser
monitorado e a função de callback que será executada quando esse evento for disparado pelo
Client.
Na função de callback utilizando o parâmetro do socket passado na conexão é atachado
dois eventos no socket ("userconected" e "disconnect"), desta forma o Server irá monitorar
esses dois eventos que serão emitidos pelo Client.
Linhas #32 a #38: é informado através do método "on" o monitoramento do
evento "userconected" onde este utilizando o método "emit" do socket será enviado uma
mensagem para o usuário referente ao socket passado via parâmetro para o
evento "connection". Já na linha #37 será enviada uma mensagem para todos os usuários
conectados, menos o usuário do socket corrente. O método "broadcast" envia uma
mensagem para todos os demais canais/usuários que estão conectados no Server menos o
usuário do socket atual.
Linhas #43 a #46: é informado através do método "on" o monitoramento do
evento "disconnect" onde este irá emitir uma mensagem para os demais usuários conectados
informando que o usuário referente ao atual socket saiu da página.
Pelo código conseguimos ver como utilizar o monitoramento dos eventos utilizando os
métodos:
- on: para informar o evento a ser monitorado e a função de callback que será executada
quando o evento for disparado pelo Client. Note que nenhuma das funções
recebem parâmetros pelo Client, mas podemos também informar parâmetros para o Server
assim como informamos para o Cliente (linha #34 é um exemplo disso).
- emit: este método irá emitir o evento para o Client/Server. Nele devemos informar no
primeiro parâmetro o nome do evento e os demais itens informados serão os parâmetros que
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 16
o Client/Server irá receber na função de callback.
- broadcast: este atributo utilizando em conjunto com o método "emit" irá emitir o evento
para todos os usuários conectados menos o atual usuário.
2º Passo - Criando a estrutura no Client side: neste passo iremos criar uma página HTML para
demonstrar o monitoramento dos eventos disparados pelo Server side. Como mencionado no
início do poste irei utilizar um servidor Web local para a demonstração do exemplo com
socket.io. Então vamos a configuração.
- Crie uma pasta no DOCUMENT_ROOT do seu servidor Web com o nome "socketio_exemplo"
crie um arquivo HTML com o nome "socket.html" e com o conteúdo abaixo:
<!DOCTYPE html>
<html>
<head>
<title>Exemplo utilizando socket.io</title>
<meta charset="utf-8" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<!-- CSS -->
<style type="text/css">
h2 {
color: #439;
font-size: 120%;
}
</style>
<!-- JS -->
<script type="text/javascript" src="http://localhost:8088/socket.io/socket.io.js"></script>
<script type="text/javascript">
// Criando a conexão com o Socket.io
var socket = io.connect('http://localhost:8088',{
'reconnect': true
,'reconnection delay': 500
,'max reconnection attempts': 1000
,'secure': false
});
// Emitindo o evento para o Server
socket.emit('userconected');
// Listeners
/**
* Monitorando o evento "showmessage" que será disparado pelo Server
* @param {String} msg Mensagem a ser exibida
*/
socket.on('showmessage', function(msg){
var messageEl = document.getElementById('message-info');
// Exibindo a mensagem enviada
messageEl.innerHTML += msg;
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 17});
</script>
</head>
<body>
<h2>Mensagens do socket.io</h2>
<div id="message-info"></div>
</body>
</html>
Detalhando o código:
Neste ponto irei detalhar somente as linhas de código que fazem a mágica acontecer, pois
no mais é só HTML e CSS.
Linha #17: nesta linha estamos solicitando o arquivo JS do socket para o Server. Note que
utilizamos o mesmo IP e porta que foi informado na configuração do socket no Server.
Linhas #20 a #25: neste bloco que estamos criando a conexão com o socket no Server, neste
momento que é disparado o evento "connection". Há algumas opções que podemos passar
para a criação do socket. Abaixo a informação de cada atributo:
- reconnect (bool): que irá informar se o socket irá tentar se conectar caso perca a conexão
com o Server.
- reconnection delay (int): informa o tempo em milissegundos que será o delay da tentativa de
conexão.
- max reconnection attemps (int): informa o valor máximo de tentativas de conexão com o
Server.
- secure (bool): informando se a conexão com o Server irá utilizar criptografia (conexões
HTTPS).
Linha #28: utilizando o método "emit" dispara o evento "userconnected" para o Server.
Linhas #36 a #41: neste bloco utilizando o método "on" é informado o monitoramento do
evento "showmessage" que será disparado pelo Server passando como parâmetro a
mensagem a ser exibida no browser do usuário.
Linha #37: utilizando o método "getElementById" do JS resgatamos a referência da DIV
onde iremos inserir o texto da mensagem enviada pelo Server.
Linha #40: utilizando a propriedade "innerHTML" do elemento inserimos o texto que é
informado pelo Server.
3º Passo - Rodando o exemplo: para executar o nosso exemplo primeiro temos que iniciar o
serviço do node.js através do nosso arquivo "socketio_exemplo.js", assim pelo prompt do
Windows vá na pasta de instalação do node.js e execute o comando "node
socketio_exemplo.js" (sem aspas) e pressione ENTER.
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 18
Veja a mensagem escrita no console (prompt do Windows) informando que o socket.io foi
iniciado.
Agora iremos acessar o nosso arquivo "socket.html" pelo servidor Web no browser
digite http://localhost/socketio_exemplo/socket.html exibindo o conteúdo conforme abaixo:
O texto "Usuário conectado no socket!!!" é exibido através do monitoramento feito nas
linhas #36 a #41 do arquivo "socket.html".
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 19
A imagem acima demonstra as mensagens que estão sendo exibidas no prompt do Window
informando o usuário conectado. Note no texto grifado em vermelho. Neste trecho o socket
está emitindo uma mensagem para o Client utilizando o evento "showmessage" passando
como parâmetro a mensagem a ser exibida no DIV.
Abra outro navegador e digite http://localhost/socketio_exemplo/socket.html será exibido
a mensagem "Outro usuário foi conectado" no primeiro browser aberto e no último será
exibido a mensagem "Usuário conectado no socket!!!".
Se você olhar novamente para o prompt do Windows verá as mensagens enviadas para os
dois sockets conectados
Pela imagem podemos ver que a mensagem "Usuário conectado no socket!!!" é disparada
duas vezes uma para o primeiro browser (Chrome) e outra para o segundo browser (Firefox),
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 20
já a mensagem "Outro usuário foi conectado" foi enviada somente para o socket já conectado
(Chrome).
2° Capítulo
Instalando o node.js no ambiente Linux e em um servidor Ubuntu 14.04
Introdução
O Node.js é uma plataforma Javascript para programação do lado servidor, que permite aos
usuários construírem aplicações de rede rapidamente. Ao levar o Javascript tanto ao front-end
quanto ao back-end, o desenvolvimento pode ser mais consistente e ser projetado dentro do
mesmo sistema.
Neste guia, vamos mostrar a você como começar com o Node.js em um servidor Ubuntu 14.04.
Se você estiver buscando criar um ambiente de produção Node.js, confira este link How To Set
Up a Node.js Application for Production.
Como Instalar a Versão Distro-Stable
O Ubuntu 14.04 contém uma versão do Node.js em seus repositórios padrão que pode ser
utilizada para fornecer facilmente uma experiência consistente entre múltiplos servidores. A
versão nesses repositórios é a 0.10.25. Esta não é a última versão, mas deve ser bastante
estável.
Para obter esta versão, temos apenas que utilizar o gerenciador de pacotes apt. Devemos
atualizar nosso índice de pacotes e, então, instalar através dos repositórios:
sudo apt-get update
sudo apt-get install nodejs
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 21
Se o pacote no repositório satisfaz suas necessidades, isto é tudo que você precisa fazer
para ter o Node.js configurado. Em muitos casos, você vai querer também instalar o npm, que
é o gerenciador de pacotes do Node.js. Você pode fazer isto digitando:
sudo apt-get install npm
Isto o permitirá instalar facilmente módulos e pacotes para utilizar com o Node.js.
Devido a um conflito com outro pacote, o executável dos repositórios do Ubuntu é chamado
nodejs em vez de node. Tenha isso em mente quando estiver executando software.
Abaixo, discutiremos alguns métodos mais flexíveis de instalação.
Como Instalar Utilizando um PPA
Uma alternativa que pode lhe trazer a versão mais recente do Node.js é adicionar um PPA
(arquivo de pacotes pessoais) mantido pelo NodeSource. Isto terá provavelmente versões mais
atualizadas do Node.js do que os repositórios oficiais do Ubuntu.
Primeiro, você precisa instalar o PPA de modo a obter acesso ao seu conteúdo:
curl -sL https://deb.nodesource.com/setup | sudo bash -
O PPA será adicionado à sua configuração e o seu cache local de pacotes será atualizado
automaticamente. Depois de executar o script de configuração do nodesource, você pode
instalar o pacote Node.js da mesma forma que você fez acima:
sudo apt-get install nodejs
O pacote nodejs contém o binário nodejs bem como o npm, de forma que você não precisa
instalar o npm separadamente. Contudo, para que alguns pacotes do npm funcionem (tais
como aqueles que requerem compilação do fonte), você precisará
instalar o pacote build-essentials:
sudo apt-get install build-essential
Como Instalar Utilizando o NVM
Uma alternativa para instalação do Node.js através do apt é usar uma ferramenta
especialmente projetada, chamada nvm, que significa "Node.js version manager" ou
"Gerenciador de Versão do Node.js".
Usando o nvm você pode instalar múltiplas versões, auto-contidas do Node.js que o
permitirá controlar seu ambiente mais facilmente. Ele dará a você acesso sob demanda às mais
novas versões do Node.js, mas também o permitirá apontar versões prévias que suas
aplicações podem depender.
Para começar, precisaremos obter os pacotes de software do nosso repositório Ubuntu, que
nos permitirão compilar pacotes de fontes. O script nvm aproveitará estas ferramentas para
construir os componentes necessários:
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 22sudo apt-get update
sudo apt-get install build-essential libssl-dev
Uma vez que os pacotes requeridos estejam instalados, você pode baixar o script de
instalação do nvm da página do projeto GitHub. O número de versão pode ser diferente, mas
em geral, você pode baixar e o instalar com a seguinte sintaxe:
curl https://raw.githubusercontent.com/creationix/nvm/v0.16.1/install.sh | sh
Isto irá baixar o script e o executar. Ele irá instalar o software dentro de um subdiretório do
seu diretório home em ~/.nvm. Ele irá adicionar também as linhas necessárias ao seu arquivo
~/.profile para utilizar o arquivo.
Para obter acesso à funcionalidade do nvm, você precisará sair e se logar novamente, ou
você pode varrer o arquivo ~/.profile de modo que sua sessão atual saiba sobre as alterações:
source ~/.profile
Agora que você tem o nvm instalado, você pode instalar versões isoladas do Node.js.
nvm ls-remote
. . .
v0.11.6
v0.11.7
v0.11.8
v0.11.9
v0.11.10
v0.11.11
v0.11.12
v0.11.13
Como você pode ver, a versão mais recente no momento da redação deste artigo é a
v0.11.13. Você pode instalá-la digitando:
nvm install 0.11.13
Usualmente, o nvm irá utilizar a versão mais recente instalada. Você pode dizer
explicitamente ao nvm para utilizar a versão que acabamos de baixar digitando:
nvm use 0.11.13
Quando você instala o Node.js utilizando o nvm, o executável é chamado node. Você pode
ver a versão atualmente sendo utilizada pelo shell digitando:
node -v
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 23
v.0.11.13
Se você tiver múltiplas versões do Node.js, você pode ver o que está instalado digitando:
nvm ls
Se desejar tornar padrão uma das versões, você pode digitar:
nvm alias default 0.11.13
Esta versão será automaticamente selecionada quando uma nova sessão for iniciada. Você
também pode referenciá-la pelo apelido desta maneira:
nvm use default
Cada versão do Node.js irá manter o controle de seus próprios pacotes e tem npm
disponível para gerenciá-los.
Você pode ter pacotes de instalação do npm para o diretório ./node_modules do projeto
Node.js utilizando o formato normal:
npm install Express
Se você deseja instalá-lo globalmente (disponível para outros projetos utilizando a mesma
versão de Node.js), você pode adicionar o flag -g:
npm install -g Express
Isto instalará o pacote em:
~/.nvm/node_version/lib/node_modules/package_name
Instalando globalmente permitirá a você executar comandos através da linha de comando,
mas você terá que vincular o pacote em sua esfera local para exigi-lo de dentro de um
programa:
npm link Express
Você pode aprender mais sobre as opções disponíveis com o nvm digitando:
nvm help
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 24
3° Capítulo
Primeiros passos com node.js
O que é Node.js?
Node.js é uma plataforma para desenvolvimento de aplicações server-side baseadas em
rede utilizando JavaScript e o V8 JavaScript Engine, ou seja, com Node.js podemos criar uma
variedade de aplicações Web utilizando apenas código em JavaScript.
Em uma primeira análise essa informação pode não parecer tão interessante, uma vez que
existem diversas outras maneiras em que esses tipos de serviços podem ser implementados.
Mas se pensarmos um pouco mais sobre as demandas de aplicações na internet e o modo em
que o código em JavaScript pode ser estruturado, vamos nos deparar com uma gama de novas
possibilidades para desenvolvimento Web, e provavelmente nos juntar à crescente
comunidade que tem adotado essa plataforma.
Embora Node.js tenha muito em comum com os servidores tradicionais como Apache e IIS,
podemos entender melhor essa relação se considerarmos as diferenças. Node.js é
extremamente simples, por isso pode não ser a solução ideal para todos os casos. Enquanto os
servidores tradicionais são mais robustos e preparados para situações mais complexas, e isso
invariavelmente vai consumir mais recursos das máquinas do que Node.js.
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 25
O web server ‘Olá mundo!’
Ok, então vamos construir alguma coisa.
Nosso primeiro exemplo é um servidor que retorna a string ‘Olá mundo’ para qualquer
requisição. Para fazer isso utilizando Node você vai precisar de criar um arquivo JavaScript que
pode ser chamado olanode.js e de três minutos do seu tempo.
Escreva o seguinte código no seu arquivo:
1. var http = require('http');
2. http.createServer(function(req,res) {
3. res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });
4. res.end('Olá mundo!');
5. }).listen(3000);
6. console.log('Servidor iniciado em localhost:3000. Ctrl+C para encerrar…');
Para executar o seu programa Node basta o seguinte comando no seu terminal:
1. $ node olanode.js
Para testar seu servidor você pode acessar localhost:3000 no seu navegador ou utilizar linha
de comando com o comando curl (em uma nova instância do terminal) como mostrado a
seguir:
1. $ curl http://0.0.0.0:3000/
2. > Olá mundo!
Caso você prefira retornar algum html válido para o navegador, basta alterar 'text/plain'
para 'text/html' no código acima e utilizar uma tag html legal como <h2>, como foi feito a
seguir:
1. var http = require('http');
2. http.createServer(function(req,res) {
3. res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
4. res.end('<h2> Olá mundo! </h2>');
5. }).listen(3000);
6. console.log('Servidor iniciado em localhost:3000 . Ctrl+C para encerrar…’);
Orientado a eventos e não obstrutivo
Orientado a eventos
Vamos aproveitar este momento de euforia após a construção do seu primeiro servidor
para aprender um pouco mais sobre Node.js.
Quando estamos desenvolvendo com Node.js devemos utilizar uma abordagem orientada a
eventos, isso quer dizer que o desenvolvedor precisa conhecer os eventos que serão emitidos
em diferentes momentos da execução e também saber como ouvi-los para executar as
operações necessárias.
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 26
Um bom exemplo de orientação a eventos está na construção de interfaces de usuário.
Muitas vezes utilizamos elementos como por exemplo os botões que ao serem clicados
emitem um evento do tipo click ao qual podemos ouvir e executar alguma operação.
No nosso exemplo anterior utilizamos esse conceito quando chamamos método listen do
objeto do tipo web server e passamos como parâmetro a porta 3000, com isso fizemos que a
nossa aplicação ouvisse ao evento que é emitido sempre que alguém faz uma requisição no
localhost:3000 e a nossa resposta foi servir a string ou a página html. Este evento é chamado
request.
Para ilustrar estes conceitos, podemos escrever o nosso exemplo anterior em uma sintaxe
alternativa da seguinte forma:
1. var http = require('http');
2. var server = http.createServer();
3. server.on('request', function(req,res) {
4. res.writeHead(200, { 'Content- Type': 'text/html; charset=utf-8' });
5. res.end('<h2> Olá mundo! </h2>');
6. });
7. server.listen(3000);
8. console.log('Servidor iniciado em localhost:3000. Ctrl+C para encerrar…’);Dessa forma podemos ver claramente a maneira em que o Node.js opera para servir a sua
página. Utilizamos o método on do nosso objeto server para ouvir ao evento request e fazer as
operações. E definimos que estamos servindo na porta 3000.
Não obstrutivo
Todos os recursos presentes no Node.js e também a maioria das bibliotecas feitas para ele
adotaram um padrão não obstrutivo de escrever código, isso quer dizer que em Node.js você
geralmente vai conseguir estruturar seu código de uma maneira que operações que não
dependem de nada que está sendo executado possam ser executadas de forma independente.
Para mostrar um pouco como isso funciona, vamos um programa que escreve duas frases
no terminal, porém uma dessas frases precisa ser carregada da memória antes de ser
impressa.
1. var frase;
2. carregaFrase = function (callback) {
3. setTimeout(function() {
4. //Simula leitura da frase no banco de dados.
5. frase = "Minha frase obstrutiva";
6. callback();
7. }, 3000)
8. }
9. imprimeFrase = function () {
10. console.log(frase);
11. }
12. carregaFrase(imprimeFrase);
13. console.log(“Olá");
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 27
Nesse exemplo foi criada uma função chamada carregaFrase cujo objetivo é ler uma
determinada frase de uma fonte de dados, e uma outra função chamada imprimeFrase que
imprime o valor de uma determinada variável no console. Como dependemos da leitura da
frase na fonte de dados para imprimir o valor, passamos a função que imprime como
parâmetro para a função de leitura para que possamos executar essa função quando a leitura
for concluída. Esse tipo de função que é passada como parâmetro dessa maneira é chamada
de callback.
Ao executar este exemplo com Node.js ou qualquer mecanismo JavaScript você vai
perceber que a frase “Olá” será impressa antes da outra frase mesmo estando posicionada
depois no código, isso se deve ao fato de sua execução não depender de nada enquanto a
execução da outra frase depende de uma operação que leva 3 segundos.
Este é um exemplo extremamente simples de como criar um código não obstrutivo,
portanto use sua imaginação para imaginar cenários em que isso pode ser útil.
Observe que no nosso primeiro exemplo com Node.js tanto a função on quanto a função
createServer podem receber uma função de callback.
4° Capítulo
Uma previa introdução sobre a plataforma node.js
Já tenho o Node instalado, e agora o que fazer?
Uma vez instalado, agora você tem acesso a um novo comando chamado node. Você pode
usar o comando node de duas formas diferentes. A primeira é sem argumentos. Isto irá abrir
um shell interativo (REPL: read-eval-print-loop), onde você pode executar código JavaScript
puro.
$ node
> console.log('Hello World');
Hello World
undefined
No exemplo acima eu digitei console.log('Hello World') dentro do shell e apertei enter. O
Node vai então executar o código e nós podemos ver nossa mensagem registrada. Ele também
imprime undefined pelo fato de sempre mostrar o valor de retorno de cada comando, e
console.log não retorna nada.
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 28
A outra forma de rodar o Node é fornecendo a ele um arquivo JavaScript para execução.
Isto será na maioria das vezes a maneira como você irá utilizá-lo.
hello.js
console.log('Hello World');
$ node hello.js
Hello World
Neste exemplo, eu movi o comando console.log() para dentro de um arquivo e então passei
este arquivo para o comando node como um argumento. O Node então roda o JavaScript
contido neste arquivo e imprime "Hello World".
Fazendo Algo Útil
Rodar código JavaScript é divertido e tal, mas não é muito útil. Ai é onde o Node.js também
inclui um poderoso conjunto de bibliotecas (módulos) para se fazer coisas reais. No primeiro
exemplo eu vou abrir um arquivo de registros e analisá-lo.
example-log.txt
2013-08-09T13:50:33.166Z A 2
2013-08-09T13:51:33.166Z B 1
2013-08-09T13:52:33.166Z C 6
2013-08-09T13:53:33.166Z B 8
2013-08-09T13:54:33.166Z B 5
O que esses dados registrados significam não importa, mas basicamente cada mensagem
contém uma data, uma letra e um valor. Eu quero somar os valores para cada letra.
A primeira coisa que nós precisamos fazer é ler o conteúdo do arquivo.
my-parser.js
// Carregando o módulo fs (filesystem)
var fs = require('fs');
// Leia o conteúdo do arquivo para a memória
fs.readFile('example-log.txt', function ( err, logData ) {
// Se um erro ocorrer, será lançada uma
// exceção, e a aplicação irá ser encerrada
if ( err ) throw err;
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 29
// logData é um Buffer, converta-o para string
var text = logData.toString();
});
Felizmente o Node.js faz a entrada e saída (I/O) do arquivo facilmente com o módulo
embutido filesystem (fs). O módulo fs tem uma função chamada readFile que pega o caminho
de um arquivo e um callback. O callback vai ser invocado quando o arquivo for lido por
completo. O dado do arquivo vem na forma de um Buffer, que é basicamente um array de
bytes. Nós podemos convertê-lo para uma string usando a função toString().
Agora vamos adicionar o parsing (analisador).
my-parser.js
// Carregando o módulo fs (filesystem)
var fs = require('fs');
// Leia o conteúdo do arquivo para a memória
fs.readFile('example-log.txt', function ( err, logData ) {
// Se um erro ocorrer, será lançada uma
// exceção, e a aplicação irá ser encerrada
if ( err ) throw err;
// logData é um Buffer, converta para string
var text = logData.toString();
var results = {};
// Quebrando o arquivo em linhas
var lines = text.split( '\n' );
lines.forEach(function ( line ) {
var parts = line.split( ' ' );
var letter = parts[ 1 ];
var count = parseInt( parts[ 2 ] );
if ( !results[ letter ] ) {
results[ letter ] = 0;
}
results[ letter ] += parseInt( count );
});
console.log( results );
// { A: 2, B: 14, C: 6 }
});
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 30
Agora vamos passar este arquivo como um argumento para o comando node e ele vai
imprimir o resultado e sair.
$ node my-parser.js
{ A: 2, B: 14, C: 6 }
Eu uso muito o Node.js para scripts como este. É uma alternativa muito mais simples e
poderosa que os scripts bash.
Callbacks Assíncronos
Como você viu no exemplo anterior, o padrão típico do Node.js é o uso de callbacks
assíncronos. Basicamente você está dizendo a ele para fazer algo e quando isso estiver
terminado ele irá chamar sua função (callback). Isto porque o Node é de thread única.
Enquanto você está esperando pelo disparo do callback, o Node pode fazer outras coisas ao
invés de bloquear até que a requisição esteja terminada.
Isso é especialmente importante para servidores web. Isto é muito comum em aplicações
web modernas para acessar banco de dados. Enquanto você espera pelo retorno do banco de
dados, o Node pode processar mais requisições. Isso permite que você manipule milhares de
conexões conjuntas com pequenos acréscimos, comparado a criar uma thread separada para
cada conexão.
Fazendo Algo Útil - Servidor HTTP
Comodisse anteriormente, o Node não faz nada por si só. Um dos módulos embutidos
tornam a criação de servidores HTTP simples muito fácil, que é o exemplo na página inicial do
Node.js.
my-web-server.js
var http = require('http');
http.createServer(function ( req, res ) { // req = requisição, res = resposta
res.writeHead( 200, { 'Content-Type': 'text/plain' } );
res.end( 'Hello World\n' );
}).listen( 8080 );
console.log( 'Servidor rodando na porta 8080' );
Quando eu digo básico, quero dizer básico mesmo. Este não é um servidor HTTP completo.
Ele não pode servir qualquer arquivo HTML ou de imagem. De fato, não importa sua
requisição, ela vai retornar 'Hello World'. No entanto, você pode rodar isto e verá em seu
navegador no endereço http://localhost:8080 o texto "Hello World".
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 31
$ node my-web-server.js
Você pode ter percebido uma coisa diferente agora. Sua aplicação node.js não fechou. Isto
acontece pois você criou um servidor e sua aplicação node vai continuar rodando e
respondendo as requisições até que você mesmo mate o processo.
Se você quiser ter um servidor web completo, você terá que fazer este trabalho. Você deve
checar o que foi requisitado, ler os arquivos apropriados e enviar o conteúdo de volta. Pessoas
já fizeram este trabalho duro para você.
Fazendo Algo Útil – Express
Express é um framework que torna a criação de sites normais muito simples. A primeira
coisa que você tem que fazer é instalá-lo. Juntamente com o comando node, você também
tem acesso a um comando chamado npm. Esta ferramenta permite que você acesse uma
enorme coleção de módulos criados pela comunidade, e um deles é o Express.
$ cd /my/app/location
$ npm install express
Quando você instala um módulo, ele vai ser colado em uma pasta chamada node_modules
dentro do diretório da sua aplicação. Você pode agora requisitar (require) este módulo como
um módulo embutido. Vamos criar um arquivo estático básico usando o Express.
my-static-file-server.js
var express = require('express');
app = express();
app.use(express.static(__dirname + '/public'));
app.listen(8080);
$ node my-static-file-server.js
Agora você tem um servidor de arquivos estáticos bastante eficiente. Tudo que você colocar
dentro da pasta /public poderá ser requisitado pelo seu navegador e será mostrado. HTML,
imagens, enfim, tudo. Por exemplo, se você colocar uma imagem chamada my-image.png
dentro da pasta public, você pode acessá-la usando seu navegador no endereço
http://localhost:8080/my-image.png. Claro que o Express tem vários outros recursos, mas
você pode olhá-los a medida que continua desenvolvendo.
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 32
NPM
Nós usamos um pouco o NPM nas seções anteriores, mas eu quero enfatizar o quão
importante esta ferramenta se faz no desenvolvimento para Node.js. Existem milhares de
módulos disponíveis que resolvem quase todos os problemas típicos que você encontra.
Lembre-se de checar o NPM antes de re-inventar a roda. Não é inédito para uma aplicação
Node ter dezenas de dependências.
No exemplo anterior nós instalamos o Express manualmente. Se você tiver muitas
dependências, essa não será uma forma muito interessante de instalá-las. É por isso que o
NPM faz uso do arquivo package.json.
package.json.
{
"name" : "MyStaticServer",
"version" : "0.0.1",
"dependencies" : {
"express" : "3.3.x"
}
}
Um arquivo package.json contém um resumo da sua aplicação. Existem vários campos
disponíveis, sendo este apenas o mínimo. A seção dependencies (dependências) descreve o
nome e a versão dos módulos que você gostaria de instalar. Neste caso eu vou aceitar
qualquer versão do Express 3.3. Você pode listar quantas dependências quiser nesta seção.
Agora, ao invés de instalar cada dependência em separado, nós podemos rodar um simples
comando e instalar todas elas.
$ npm install
Quando você roda este comando, o npm vai verificar na pasta atual pelo arquivo
package.json. Se ele encontrar um, então irá instalar cada dependência listada.
Organização do Código
Até agora só usamos um único arquivo, que não é muito sustentável. Na maioria das
aplicações, seu código vai ser dividido em vários arquivos. Não existe nenhuma norma ou
organização imposta dizendo para onde os arquivos vão. Isto não é Rails. Não há conceitos de
views e controllers acontecendo aqui. Você pode fazer o que quiser.
Vamos refatorar o script de análise de registros (log parsing). Ele será muito mais testável e
manutenível se nós separarmos a lógica de análise (parsing) dentro de um arquivo próprio.
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 33
parser.js
// Construtor Parser
var Parser = function () {
};
// Analisa o texto especificado
Parser.prototype.parse = function ( text ) {
var results = {};
// Quebra o arquivo em linhas
var lines = text.split('\n');
lines.forEach(function ( line ) {
var parts = line.split( ' ' );
var letter = parts[ 1 ];
var count = parseInt( parts[2] );
if ( !results[ letter ] ) {
results[ letter ] = 0;
}
results[ letter ] += parseInt( count );
});
return results;
};
// Exportando o construtor Parser neste módulo
module.exports = Parser;
O que eu fiz foi criar um novo arquivo para conter a lógica da análise dos registros. Isto é
apenas JavaScript puro e existe várias formas de se encapsular este código. Eu escolhi por
definir um novo objeto JavaScript pois assim é mais fácil de se fazer testes unitários.
A parte importante para isso é a linha module.exports. Isso diz ao Node que você está
exportando deste arquivo. Neste caso exportei um construtor, então os usuários podem criar
instâncias do meu objeto Parser. Você pode exportar qualquer coisa que quiser.
Agora vamos ver como importar este arquivo e fazer uso do novo objeto Parser.
my-parser.js
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 34
// Requisitando o arquivo parser.js
var Parser = require('./parser');
// Carregandoo módulo fs (filesystem)
var fs = require('fs');
// Lendo o conteúdo do arquivo para a memória
fs.readFile('example-log.txt', function ( err, logData ) {
// Se um erro ocorrer, irá ser lançada
// a exceção e a app será encerrada
if ( err ) throw err;
// logData é um Buffer, converta-o para string
var text = logData.toString();
// Criando uma instância do objeto Parser
var parser = new Parser();
// Chame a função parse
console.log( parser.parse( text ) );
// { A: 2, B: 14, C: 6 }
});
Arquivos são incluídos da mesma forma que os módulos, exceto que você inclui um
caminho ao invés de um nome. A extensão .js é implícita, então você pode omití-la se quiser.
Tendo sido exportado um construtor, é isso que vai ser retornado da declaração require. Eu
posso agora criar instâncias do meu objeto Parser e usá-las.
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 356° Capítulo
Conceitos Básicos sobre Criação de uma Aplicação Cordova
Instale o Cordova em seu sistema local para encapsular uma aplicação HTML5 como
aplicação móvel nativa com o NetBeans IDE. Você usará npm, o gerenciador de pacote NodeJS,
para instalar e atualizar o Cordova. Confirme também se o Git está instalado em seu sistema
local e configurado corretamente. O Cordova usa o Git para recuperar em um repositório
qualquer arquivo de código-fonte Cordova quando você encapsula a aplicação como móvel
nativa.
A maioria das etapas a seguir deste exercício serão executadas na janela do terminal.
1. Faça download e instale o Node.js, se não estiver instalado.
Você pode fazer o download do instalador no site do Node.js.
2. Abra uma janela de terminal.
3. Execute o comando a seguir para confirmar se o Node.js está instalado.
$ node -v
Se o node.js estiver instalado, você verá uma versão impressa na janela do terminal.
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 36
Observações.
Se estiver protegido por proxy, você precisará configurar o node.js para usar o proxy
no acessar à rede. Execute os comandos a seguir para configurar o proxy, substituindo
http://proxy:8080 pelo seu proxy.
$ sudo npm config set proxy http://proxy:8080
$ sudo npm config set https-proxy http://proxy:8080
Execute o seguinte comando para exibir as definições de configuração atuais.
$ npm config list
Para obter informações adicionais sobre a configuração do node.js, consulte
https://npmjs.org/doc/config.html.
Execute o comando a seguir para instalar o Cordova.
$ npm install -g cordova
Observações.
Confirme se a configuração do proxy está correta, caso veja uma mensagem de erro na
janela do terminal quando executar o comando de instalação.
Você pode executar o seguinte comando que atualiza o Cordova para a versão mais
recente.
$ npm update -g cordova
Execute o seguinte comando para confirmar se o Cordova está instalado e exibir a
versão.
$ cordova --version
Se o Cordova estiver instalado, você verá uma versão impressa na janela do terminal.
Faça o download e instale o sistema de controle de versão Git se não estiver instalado.
Você pode fazer o download do instalador no site do Git.
Observação. Adicione o Git à variável de ambiente Path.
Execute o comando a seguir para confirmar se o Git foi instalado.
$ git --version
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 37
1. Se o Git estiver instalado, você verá uma versão impressa na janela do terminal.
Observações.
Se estiver protegido por proxy, você precisará configurar o Git para usar o proxy no
acessar à rede. Execute os comandos a seguir para configurar o proxy, substituindo
http://proxy:8080 pelo seu proxy.
$ git config --global http.proxy http://proxy:8080
$ git config --global https.proxy http://proxy:8080
Execute o seguinte comando para exibir as definições de configuração atuais.
$ git config --list
Para obter informações adicionais sobre a configuração do Git, consulte as instruções
de configuração em http://git-scm.com/book/en/Getting-Started-First-Time-Git-Setup.
Agora você tem todas as ferramentas de que precisa para desenvolver e encapsular uma
aplicação móvel nativa no IDE. No próximo exercício, você usará o assistente de Novo Projeto
para criar a aplicação.
Criando uma Aplicação Cordova
Neste exercício, você usará o assistente de Novo Projeto no IDE para criar uma nova
aplicação Cordova. Crie uma aplicação Cordova selecionando o modelo Hello World do
Cordova como modelo de site no assistente de Novo Projeto. O Cordova é uma aplicação
HTML5 com algumas bibliotecas e arquivos de configuração adicionais. Se você tiver uma
aplicação HTML5 existente, poderá usar a janela Propriedades do Projeto no IDE para
adicionar os códigos-fonte do Cordova e outros arquivos exigidos para encapsular a aplicação
como Cordova.
Neste tutorial, você criará um projeto HTML5 bem básico que tem um arquivo index.html e
alguns arquivos JavaScript e CSS. Você selecionará algumas bibliotecas jQuery JavaScript
quando criar o projeto no assistente.
1. Selecione Arquivo > Novo Projeto (Ctrl-Shift-N; ⌘-Shift-N no Mac) no menu
principal para abrir o assistente Novo Projeto.
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 38
2. Selecione a categoria HTML5 e, em seguida, selecione Aplicação Cordova.
Clique em Próximo.
3. Digite CordovaMapApp como Nome do Projeto e especifique o diretório no seu
computador onde você quer salvar o projeto. Clique em Próximo.
4. Na Etapa 3. Modelo de Site, confirme se Fazer Download do Modelo On-line
está selecionado e se o modelo Cordova Hello World está selecionado na lista.
Clique em Próximo.
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 39
1. Observação: Você deve estar on-line para criar um projeto baseado em um dos
modelos on-line da lista.
2. Na Etapa 4. Arquivos JavaScript, selecione as bibliotecas JavaScript jquery e
jquery-mobile no painel Disponível e clique no botão de seta para a direita ( > )
para mover as bibliotecas selecionadas para o painel Selecionado do
assistente. Por default, as bibliotecas são criadas na pasta js/libraries do
projeto. Para este tutorial, você utilizará as versões "minimizadas" das
bibliotecas JavaScript.
Você pode usar o campo de texto no painel para filtrar a lista de bibliotecas
JavaScript. Por exemplo, digite jq no campo para ajudá-lo a encontrar as
bibliotecas jquery. Você pode usar Ctrl-clique nos nomes das bibliotecas para
selecionar várias bibliotecas.
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 40
1. Observações.
Você pode clicar no número de versão da biblioteca na coluna Versão para
abrir uma janela pop-up que permite selecionar a ordem das versões de
biblioteca. Por default, o assistente exibe a versão mais recente.
As versões minimizadas das bibliotecas JavaScript são versões compactadas e o
código não é abrangente quando exibido em um editor.
Na Etapa 5. Suporte a Cordova, use os valores padrão. Clique em Finalizar
para concluir o assistente.
Quando você clicar em Finalizar, o IDE criará o projeto e exibirá um nó para
o projeto na janela Projetos,e abrirá o arquivo index.html no editor
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 41
Se você expandir a pasta js/libs na janela Projetos, poderá ver que as bibliotecas JavaScript
que você especificou no assistente do Novo Projeto foram automaticamente adicionadas ao
projeto. Você pode remover uma Biblioteca JavaScript de um projeto clicando com o botão
direito do mouse no arquivo JavaScript e escolhendo Deletar no menu pop-up.
Para adicionar uma biblioteca JavaScript a um projeto, clique com o botão
direito do mouse no nó do projeto e escolha Propriedades para abrir a janela
Propriedades do Projeto. Você pode adicionar bibliotecas no painel Bibliotecas
JavaScript da janela Propriedades do Projeto. Como alternativa, é possível
copiar um arquivo JavaScript que está no sistema local diretamente na pasta js.
Agora você pode testara execução do projeto e ver se ele foi implantado no
emulador do seu dispositivo móvel de destino.
7. Clique no ícone de seleção do browser na barra de ferramentas e confirme se o seu
emulador de dispositivo móvel de destino está selecionado na coluna Cordova da
tabela. Na coluna Cordova, você pode selecionar o Emulador do Android ou do iOS
(exige OS X e XCode).
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 42
8. Clique no ícone Executar na barra de ferramentas.
Quando você escolhe Executar, o IDE implanta a aplicação Cordova no emulador.
Observação. Se você estiver implantando no Simulador do iOS, o simulador deverá ser aberto
automaticamente. Se estiver implantando a aplicação em um emulador do Android, você
precisará configurar e iniciar o emulador antes de executar a aplicação. Para ver um screencast
que demonstre a implantação de uma aplicação Cordova no emulador do Android, assista ao
Vídeo de Conceitos Básicos sobre Desenvolvimento Cordova.
Modificando a Aplicação
Neste exercício, você editará os arquivos index.html e index.js. Você substituirá o código
gerado pelo modelo Cordova Hello World pelo código de exibição de um mapa do local atual
na aplicação. Além disso, modificará a configuração padrão do Cordova para remover os plug-
ins do Cordova que não são necessários na aplicação.
Editando o Arquivo HTML
Neste exercício, edite o arquivo HTML no editor de código-fonte para adicionar referências
a bibliotecas e arquivos CSS e para adicionar os elementos da página.
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 43
1. Abra index.html no editor (se ainda não estiver aberto).
No editor, você pode ver que o IDE gerou um código baseado no modelo Cordova
Hello World.
2. No editor, adicione referências a bibliotecas JavaScript e arquivos CSS do jQuery que
foram adicionados quando você criou o projeto. Adicione o seguinte código (em
negrito) entre as tags de abertura e fechamento <head>.
3. <html>
4. <head>
5. <meta charset=UTF-8">
6. <meta name="format-detection" content="telephone=no" />
7. <meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-
scale=1, minimum-scale=1, width=device-width, height=device-height, target-
densitydpi=device-dpi">
8. <link rel="stylesheet" type="text/css" href="css/index.css" />
9.
10. <link rel="stylesheet" href="js/libs/jquery-mobile/jquery.mobile.min.css"/>
11. <script type="text/javascript" src="js/libs/jquery/jquery.min.js"></script>
12. <script type="text/javascript" src="js/libs/jquery-
mobile/jquery.mobile.min.js"></script>
13. <title>Hello World</title>
14. </head>
15. <body>
16. </html>
Adicione o link a seguir à API JavaScript do Google Maps entre as tags <head>.
<script type="text/javascript" src="http://www.google.com/jsapi"></script>
Observação. Este é um link para a v2 obsoleta da API JavaScript. Este JavaScript
funcionará para fins de demonstração neste tutorial, mas você deve usar a
versão mais nova em uma aplicação real.
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 44
Remova todo o código entre as tags <body>, exceto os seguintes links para
os arquivos JavaScript index.js e cordova.js.
<body>
<script type="text/javascript" src="cordova.js"></script>
<script type="text/javascript" src="js/index.js"></script>
</body>
</html>
O arquivo index.js foi gerado automaticamente quando você criou o projeto.
O arquivo pode ser visto sob o nó js na janela Projetos. Você modificará o
código em index.js posteriormente no tutorial.
O cordova.js não é visto na janela Projetos porque é gerado na criação da
aplicação Cordova.
5. Adicione o seguinte código (em negrito) entre as tags body.
6. <body>
7. <div data-dom-cache="false" data-role="page" id="mylocation">
8. <div data-role="header" data-theme="b">
9. <h1 id="header">Searching for GPS</h1>
10. <a data-role="button" class="ui-btn-right"
onclick="showAbout()">About</a>
11. </div>
12.
13. <div data-role="content" style="padding:0;">
14. <div id="map" style="width:100%;height:100%; z-index:50">
15. </div>
16.
17. </div>
18. <div data-role="footer" data-theme="b" data-position="fixed" >
19. <h4>Google Maps</h4>
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 45
20. </div>
21. </div>
22. <div data-dom-cache="false" data-role="page" id="about">
23. <div data-role="header" data-theme="b">
24. <a data-role="button" data-rel="back" href="#mylocation" data-
icon="arrow-l" data-iconpos="left" class="ui-btn-left">Back</a>
25. <h1>About</h1></div>
26. <div data-role="content" id="aboutContent">
27. </div>
28. <div data-role="footer" data-theme="b" data-position="fixed" >
29. <h4>Created with NetBeans IDE</h4>
30. </div>
31. </div>
32. <script type="text/javascript" src="cordova.js"></script>
33. <script type="text/javascript" src="js/index.js"></script>
34. </body>
35. </html>
Modificando a Configuração do Cordova
Neste exercício, você modificará a lista de plug-ins do Cordova que são instalados na aplicação.
1. Na janela Projetos, clique com o botão direito do mouse no nó do projeto e escolha
Propriedades no menu pop-up.
2. Selecione Cordova na lista de categorias.
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 46
1. Use a guia Aplicação para exibir e editar os detalhes de configuração do
Cordova sobre a aplicação que são especificados em config.xml.
2. Clique na guia Plug-ins do painel Cordova.
A guia Plug-ins contém dois painéis. O painel Disponível exibe uma lista dos
plug-ins do Cordova que estão disponíveis atualmente.
O painel Selecionado exibe uma lista dos plug-ins que são instalados na
aplicação. Por padrão, todos os plug-ins são instalados quando você usa o
modelo Cordova Hello World para criar a aplicação. A maioria das aplicações
não exige todos os plug-ins. Você pode usar a guia Plug-ins na janela
Propriedades do Projeto para remover os plug-ins que não são exigidos pela
aplicação.
Observação. É possível também editar os plug-ins instalados editando o
arquivo nbproject/plugins.properties no editor.
3. Remova todos os plug-ins exceto API do Dispositivo, Caixas de Diálogo
(Notificações) e Localização Geográfica. Clique em OK.
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 47
Editando o Arquivo JavaScript
Neste exercício, você removerá o código JavaScript gerado pelo modelo e adicionará alguns
métodos simples para exibir o mapa da sua localização atual.
1. Abra o index.js no editor.
O IDE gerou um código padronizado em index.js quando você criou o projeto. Nessa
aplicação, você pode removertodo o código gerado.
2. Substitua o código gerado pelo seguinte código. Salve as alterações.
3. var map;
4. var marker;
5. var watchID;
6.
7. $(document).ready(function() {
8. document.addEventListener("deviceready", onDeviceReady, false);
9. //uncomment for testing in Chrome browser
10. // onDeviceReady();
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 48
11. });
12.
13. function onDeviceReady() {
14. $(window).unbind();
15. $(window).bind('pageshow resize orientationchange', function(e) {
16. max_height();
17. });
18. max_height();
19. google.load("maps", "3.8", {"callback": map, other_params:
"sensor=true&language=en"});
20. }
21. function max_height() {
22. var h = $('div[data-role="header"]').outerHeight(true);
23. var f = $('div[data-role="footer"]').outerHeight(true);
24. var w = $(window).height();
25. var c = $('div[data-role="content"]');
26. var c_h = c.height();
27. var c_oh = c.outerHeight(true);
28. var c_new = w - h - f - c_oh + c_h;
29. var total = h + f + c_oh;
30. if (c_h < c.get(0).scrollHeight) {
31. c.height(c.get(0).scrollHeight);
32. } else {
33. c.height(c_new);
34. }
35. }
36. function map() {
37. var latlng = new google.maps.LatLng(50.08, 14.42);
38. var myOptions = {
39. zoom: 15,
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 49
40. center: latlng,
41. streetViewControl: true,
42. mapTypeId: google.maps.MapTypeId.ROADMAP,
43. zoomControl: true
44. };
45. map = new google.maps.Map(document.getElementById("map"), myOptions);
46.
47. google.maps.event.addListenerOnce(map, 'tilesloaded', function() {
48. watchID = navigator.geolocation.watchPosition(gotPosition, null, {maximumAge:
5000, timeout: 60000, enableHighAccuracy: true});
49. });
50. }
51.
52. // Method to open the About dialog
53. function showAbout() {
54. showAlert("Google Maps", "Created with NetBeans 7.4");
55. }
56. ;
57.
58. function showAlert(message, title) {
59. if (window.navigator.notification) {
60. window.navigator.notification.alert(message, null, title, 'OK');
61. } else {
62. alert(title ? (title + ": " + message) : message);
63. }
64. }
65.
66. function gotPosition(position) {
67. map.setCenter(new google.maps.LatLng(position.coords.latitude,
position.coords.longitude));
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 50
68.
69. var point = new google.maps.LatLng(position.coords.latitude,
position.coords.longitude);
70. if (!marker) {
71. //create marker
72. marker = new google.maps.Marker({
73. position: point,
74. map: map
75. });
76. } else {
77. //move marker to new position
78. marker.setPosition(point);
79. }
80. }
E depois de editado o código é só executar para ver o resultado.
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 51
7° Capítulo
Conceitos finais
JavaScript tornou-se, nos últimos anos, o herói subestimado do desenvolvimento de
aplicativos da web. Esse reconhecimento vem sendo encarado com surpresa por
desenvolvedores de software acostumados a considerar JavaScript uma "linguagem de
brinquedo". Embora haja linguagens mais populares (no sentido de que desenvolvedores
clamam sua lealdade a elas), o status exclusivo de JavaScript como a linguagem de script
padrão, independente de navegador, fez com que ela pudesse perdurar. Para desenvolvimento
na web no lado do cliente, é provavelmente a linguagem mais usada no mundo.
JavaScript também tem lugar em scripts do lado do servidor, e esse nicho está crescendo.
Embora tenha havido tentativas de JavaScript no lado do servidor no passado, nenhuma gerou
tanta animação quanto Node.js, ou Node.
Projetado para auxiliar desenvolvedores a criar programas de rede escaláveis, Node é um
ambiente de programação do lado do servidor que praticamente reinventou JavaScript para
uma nova geração de desenvolvedores. Para muitos desenvolvedores Java, a principal atração
do Node é sua abordagem nova para a simultaneidade de software. Embora a plataforma Java
continue evoluindo em sua abordagem da simultaneidade (com melhorias muito esperadas
em Java 7 e Java 8), o fato é que Node atende uma necessidade, e faz isso da forma mais leve
que muitos desenvolvedores Java adotaram recentemente. Como os scripts do lado do cliente
com JavaScript, os scripts do lado do servidor no ambiente Node são bons porque funcionam,
e funcionam em uma área na qual muitos desenvolvedores Java enfrentam desafios
atualmente.
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 52
Apresento a revolução dos scripts do lado do servidor que é o Node. Começaremos com
uma visão geral arquitetural do que torna o Node especial, e em seguida eu mostrarei como
desenvolver rapidamente um aplicativo da web escalável que usa MongoDB para persistência
de dados. Você verá em primeira mão como o Node é divertido, e como ele pode ser usado
rapidamente para montar um aplicativo da web funcional.
A simultaneidade conduzida por evento de Node
Node é um ambiente de E/S escalável, conduzido por evento, desenvolvido com base no
mecanismo JavaScript V8 do Google. Google V8 na verdade compila JavaScript em código de
máquina nativo antes da execução, o que resulta em desempenho extremamente rápido no
tempo de execução — algo que não é geralmente associado a JavaScript. Dessa forma, Node
permite desenvolver rapidamente aplicativos de rede extremamente rápidos e altamente
simultâneos.
E/S conduzida por evento pode soar estranho para um desenvolvedor Java, mas não é tão
novo assim. Em vez do modelo de programação multiencadeado com o qual estamos
acostumados na plataforma Java, a abordagem de Node para simultaneidade tem um único
encadeamento, com a adição de um loop de eventos. Esse desenvolvimento do Node permite
E/S sem bloqueio ou assíncrona. No Node, chamadas que geralmente bloqueariam, como
espera por resultados de consulta de banco de dados, não bloqueiam. Em vez de esperar que
atividades caras de E/S sejam concluídas, um aplicativo Node emite um retorno de chamada.
Quando um recurso é retornado, o retorno de chamada anexado é chamado de forma
assíncrona.
A simultaneidade simplesmente funciona em programas Node. Se eu quisesse executar o
cenário anterior na plataforma Java, poderia escolher entre abordagens complexas e
demoradas — de encadeamentos tradicionais a bibliotecas mais novas em Java NIO e até o
pacote java.util.concurrent melhorado e atualizado. Embora a simultaneidade de Java seja
eficiente, pode ser difícil de entender — o que se traduz em código! Em comparação, o
mecanismo de retorno de chamada do Node está integrado na linguagem; não são necessários
desenvolvimentos especiais como synchronized para fazê-la funcionar. O modelode
simultaneidade do Node é extremamente simples, e isso o torna acessível para um público
maior de desenvolvedores.
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 53
A sintaxe de JavaScript do Node também economiza bastante digitação. Com pouco código
é possível desenvolver um aplicativo da web rápido e escalável, capaz de lidar com diversas
conexões simultâneas. Isso pode ser feito na plataforma Java, mas é necessário mais linhas de
código e diversas bibliotecas e desenvolvimentos adicionais. E não precisa se preocupar em
navegar um ambiente de programação novo: Node é fácil de aprender se você sabe um pouco
de JavaScript, e eu aposto que você sabe.
Por que escolher Node.js?
A abordagem da plataforma Java para simultaneidade ajudou a estabelecer sua posição de
liderança no desenvolvimento corporativo, e isso não deve mudar. Estruturas como Netty (e
Gretty; consulte Recursos) e bibliotecas de núcleo como NIO, além de java.util.concurrent,
tornaram a JVM uma escolha preferencial para simultaneidade. O que o Node tem de especial
é que se trata de um ambiente de desenvolvimento moderno especificamente projetado para
resolver os desafios da programação simultânea. O paradigma de programação conduzido por
eventos de Node faz com que bibliotecas adicionais não sejam necessárias para fazer a
simultaneidade funcionar, e isso é uma boa notícia para desenvolvedores de olho em
hardware com diversos núcleos.
Express cuida de JSON
JavaScript e JSON são parentes próximos, o que torna o gerenciamento de Json no Express o
mais simples possível. Nesta seção, iremos incluir um pouco mais de código no aplicativo
esqueleto da Listagem 2, para que possamos obter um documento JSON recebido e imprimi-lo
na saída padrão. Após isso, iremos persistir tudo em uma instância do MongoDB.
O documento recebido será semelhante à Listagem 3 (observe que eu omiti informações de
local devido ao espaço):
Lista 3. Comida de graça no Freddie Fingers!
{
"deal_description":"free food at Freddie Fingers",
"all_tags":"free,burgers,fries"
}
A Listagem 4 inclui funcionalidade para analisar o documento recebido:
Lista 4. Express analisa JSON
app.use(express.bodyParser());
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 54
app.put('/', function(req, res) {
var deal = req.body.deal_description;
var tags = req.body.all_tags;
console.log("deal is : " + deal + " and tags are " + tags);
res.contentType('json');
res.send(JSON.stringify({ status: "success" }));
});
Observe que a Listagem 4 inclui uma linha que orienta o Express a usar bodyParser. Isso nos
permitirá facilmente (e eu realmente quero dizer facilmente) obter atributos de um
documento JSON recebido.
Dentro do retorno de chamada put há código para obter os valores dos atributos
deal_description e all_tags de um documento recebido. Observe a facilidade com que
podemos capturar os elementos individuais de um documento solicitado: neste caso,
req.body.deal_description obtém o valor de deal_description.
Teste!
Também é possível testar essa implementação. Basta parar sua instância do magnus-server
e reiniciá-la, e em seguida usar um PUT de HTTP para enviar um documento JSON para seu
aplicativo Express. Primeiro, você deve ver uma resposta de sucesso. Em seguida, o Express
deve registrar na saída padrão os valores enviados. Com meu documento de Freddie Fingers,
eu recebo esta saída
deal is : free food at Freddie Fingers and tags are free, burgers, fries.
Persistência com Node
Temos um aplicativo funcional que recebe um documento JSON, analisa-o e retorna uma
resposta. Agora precisamos incluir alguma lógica de persistência. Como sou fã do MongoDB
(consulte Recursos), eu optei por persistir os dados por meio de uma instância do MongoDB.
Para tornar as coisas ainda mais vivas, iremos usar a biblioteca de terceiros Mongolian
DeadBeef, que usaremos para armazenar os valores de documentos JSON recebidos.
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 55
Mongolian DeadBeef é uma de várias bibliotecas do MongoDB disponíveis para Node. Eu a
escolhi porque o nome me agrada, e porque o espelhamento do driver MongoDB nativo me
faz sentir em casa.
Agora você já sabe que a primeira etapa para usar o Mongolian DeadBeef é atualizar o
arquivo package.json, como mostra a Listagem 5:
Lista 5. Incluindo análise de JSON
{
"name": "magnus-server",
"version": "0.0.1",
"dependencies": {
"express": "2.4.6",
"mongolian": "0.1.12"
}
}
Como estamos conectando com um armazenamento de dados do MongoDB, também é
preciso atualizar as dependências sólidas do projeto executando npm install. Para melhorar o
desempenho do driver do MongoDB do Mongolian DeadBeef, poderíamos também instalar o
analisador bson C++ nativo, algo no qual o NPM pode nos ajudar.
Para começar a usar o Mongolian DeadBeef, incluímos outro require na implementação
atual, e em seguida conectamos a instância MongoDB desejada (como mostra a Listagem 6).
Para esse exemplo, iremos conectar a uma instância hospedada no MongoHQ, um provedor de
nuvem do MongoDB.
Lista 6. Incluindo Mongolian DeadBeef no magnus-server
var mongolian = require("mongolian");
var db = new
mongolian("mongo://a_username:a_password@flume.mongohq.com:23034/magnus");
Dentro do retorno de chamada PUT, persistimos os valores do documento JSON recebido,
como mostra a Listagem 7:
Lista 7. Incluindo lógica de inserção do Mongolian
app.put('/', function(req, res) {
var deal = req.body.deal_description;
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 56
var tags = req.body.all_tags;
db.collection("deals").insert({
deal: deal,
deal_tags: tags.split(",")
})
res.contentType('json');
res.send(JSON.stringify({ status: "success" }));
});
O que é a NPM do Node.JS
NPM é o nome reduzido de Node Package Manager (Gerenciador de Pacotes do Node). A
NPM é duas coisas: Primeiro, e mais importante, é um repositório online para publicação de
projetos de código aberto para o Node.js; segundo, ele é um utilitário de linha de comando
que interage com este repositório online, que ajuda na instalação de pacotes, gerenciamento
de versão e gerenciamento de dependências..
A NPM já conta com mais de 35 mil pacotes (Jul-2013), são bibliotecas e aplicações de
código aberto, e muitas são adicionadas todos os dias. Estas aplicações podem ser encontradas
através do portal de busca da NPM. Uma vez encontrado o pacote que você deseja instalar, ele
pode ser instalado com uma única linha de comando.
Digamos que você está trabalhando duro um dia para desenvolver sua Próxima Grande
Aplicação. Então você se depara com um problema e decide que está na hora de usar aquela
biblioteca legal que você tem ouvido a respeito - vamos usar a biblioteca assincrona de Coalan
McMahon como exemplo. Felizmente a NPM é muito simples de usar, você só precisa usar o
comando npm install async, e o módulo específico será instalado no diretório atual dentro da
pasta ./node_modules/. Uma vez instalada sua pasta node_modules, você será capaz de usar
require() nela como se fossem módulos internos do seu projeto. Para compreender melhor a
função require() eu aconselhoque você leia o artigo que explica como funciona a função
require do Node.js.
Vamos ver um exemplo de pacote instalado globalmente - vamos falar do coffee-script. O
comando para o NPM é simples: npm install coffee-script -g. Para usuários do Linux este
comando irá instalar o progama e colocar um link simbólico (symlink) na pasta /usr/local/bin.
Isto permitirá você rodar o programa diretamente do console como qualquer outra ferramenta
CLI (Command-Line Interface). Neste caso, rodar o comando coffee te permitirá usar o REPL do
coffee script.
Outro importante uso da NPM é o gerenciamento de dependências. Quando você tem um
projeto Node com um arquivo package.json, você pode rodar o comando npm install na pasta
raiz do seu projeto e a NPM vai isntalar todas as dependências listadas no package.json. Isto
faz a instalação de projetos Node de repositórios Git muito mais fáceis! Vamos usar o exemplo
do vows, um dos frameworks de testes do Node, ele pode ser instalado através do Git, e suas
dependências: eyes, diff e glob podem ser automáticamente instaladas utilizando uma única
linha de comando da NPM.
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 57
Observe os comandos para clonar o projeto vows do github utilizando o git, e instalar suas
dependências listadas no arquivo package.json:
git clone https://github.com/cloudhead/vows.git
cd vows
npm install
Após rodar estes comandos, você vai ver a pasta node_modules contendo todas as
dependências especificadas no package.json.
Como usar o util.inspect em NodeJS
O NodeJS fornece uma útil função para propósitos de debugação que retorna uma
representação em texto de um objeto. util.inspect pode ser um salva-vidas ao se trabalhar
com propriedades de objetos grandes e complexos.
O módulo util do NodeJS contém uma série de métodos utilizados para formatar texto,
debugar, imprimir mensagens no console, checar objetos (util.isArray(objeto),
util.isRegExp(objeto), util.isDate(objeto) e util.isError(objeto)) e um método de herança
(util.inherits(construtor, superConstrutor)). Neste artigo veremos o método util.inspect.
A seguir há um exemplo simples, util.inspect pode ser usado com qualquer objeto e uma
boa demonstração pode ser usá-lo nos objetos embutidos do Node. Tente o código abaixo no
REPL do Node. Caso você não conheça o REPL, ou não saiba como acessá-lo, eu te aconselho a
ler nosso artigo explicando como usar o REPL do Node.
> var util = require('util')
undefined
> util.inspect(console)
'{ log: [Function],\n info: [Function],\n warn: [Function],\n error: [Function],\n dir:
[Function],\n time: [Function],\n timeEnd: [Function],\n trace: [Function],\n assert:
[Function] }'
Como você pode se recordar, a cada comando passada para o REPL ele imprime o retorno
do comando. O que nos interessa aqui é o retorno do comando util.inspect(console) que pode
ser visto na linha abaixo deste comando. Podemos ver que o comando nos retornou uma
string contendo todas as funções enumeráveis deste módulo.
Então nós sabemos que a função util.inspect retorna uma string contendo as propriedades
enumeráveis de qualquer objeto e também é válido acrescentar que a função console.dir é um
envólucro em torno de util.inspect, utilizando seus argumentos padrões e imprimindo seu
retorno na tela. Ao se imprimir o retorno do util.inspect utilizando a função console.log o
console utilizará a formatação contida na string, como a quebra de linhas e a exibição de cores.
> console.log(util.inspect(console))
{ log: [Function],
info: [Function],
warn: [Function],
error: [Function],
dir: [Function],
time: [Function],
timeEnd: [Function],
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 58
trace: [Function],
assert: [Function] }
undefined
util.inspect pode também ser passada com vários argumentos opcionais, apresentados aqui
com seus valores padrões:
util.inspect(object, showHidden=false, depth=2, colors=false, customInspect=true);
Por exemplo, util.inspect(meuObjeto, true, 7, true, false) poderia inspecionar meuObjeto,
mostrando todos as propriedades ocultas e não ocultas até a profundidade 7, colorir a saída e
a função inspect() definida no objeto não será chamada.
O argumento opcional depth (profundidade em inglês) é o número de níveis de
profundidade de um objeto que será feita a recursão, seu valor padrão é 2. Isso é útil para
objetos grandes e complicados. Definindo este valor como null vai forçar a recursão até atingir
o último nível de profundidade. Para observar seu comportamento você pode inserir os
comandos a seguir no REPL do Node.
var http = require('http');
console.log(util.inspect(http, false, 1));
console.log(util.inspect(http, false, 2));
O argumento opicional showHidden é um booleano que determina se vai ou não exibir as
propriedades não-enumeradas de um objeto, seu valor padrão é false o que tende a resultar
em saídas muito mais legíveis. Isso não é algo que um iniciante deve se preocupar na maior
parte do tempo, mas é válido demonstrar rapidamente. Você poderá perceber a diferença
executando os comandos a seguir no REPL do Node.
console.log(util.inspect(console, false, 1))
console.log(util.inspect(console, true, 1))
O argumento opicional color também é um valor booleano que diz se a função deve, ou
não, decorar a string de saída com códigos de cores ANSI, as cores são customizáveis.
Basicamente ela faz com que, na janela do terminal, a string de retorno possa ser impressa em
cores.
Faça o teste utilizando o comando a seguir.
var util = require('util');
console.log(util.inspect(console, false, 2, true));
Módulos do Núcleo do Node
Primeiro eu recomendo que uma versão do node esteja instalada no seu computador. Um
modo fácil para que isso aconteça e visitando nodejs.org e clique em Install.
Node tem um pequeno grupo de módulos que vem com ele por padrão (comumente
chamados como ‘núcleo do node’) eles são representados por suas API’s publicas e você utiliza
elas para escrever os seu programas. Para trabalhar com sistema de arquivos existe o módulo
fs e para redes os módulos são net (TCP), http, dgram (UDP).
Em adição ao fs e os módulos de rede existem outros módulos na base do núcleo do node.
Lá também temos um modulo assincrono para resolver consultas de DNS chamado dns, um
módulo para pegar informações especificas do sistema, por exemplo o tmpdir e ele chama os,
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 59
um outro para alocação de pedaços de binários na memória chamado buffer, varios módulos
para análise de urls e caminhos (url, querystring, path) entre outros. A maioria dos módulos
presentes no núcleo do node suportam os principais casos de uso dele: escrever rapidamente
programas que conversem com os sistema de arquivos ou rede.
Node lida com I/O com: callbacks, eventos, streams e módulos. Se você aprende como essas
quatro coisas trabalham vocês esta habil para ir em quanlquer módulo do core do node a ter
um entendimento básico sobre como a interface funciona com ele.
Evoluindo de Forma Granular em Node
Como todo boa ferramenta, o Node é bem adequado para certos casos de uso. Por
exemplo: Rails, o popular web framework, é ótimo para modelar complexas lógicas de
negócio, ex. usando código para representar a vida em um plano objetivado que vivemos
físicamente como contas, empréstimos, itinerários e inventários. Embora técnicamente seja
possível fazer o mesmo utilizando o Node, haveriadesvantagens claras sabendo que o Node é
projetado para resolver problemas de I/O e não saber sobre a parte da ‘lógica de negócio’.
Cada ferramenta tem seu foco voltado a resolver diferentes problemas. Esperamos que este
guia ajude-o a ganhar uma compreensão intuitiva dos pontos fortes do Node e você saberá
quando ele será útil.
O que está fora do escopo do Node?
Fundamentalmente o Node é somente usado como ferramenta para gerenciar I/O ao redor
do sitema de arquivos e redes, ele deixa outras funcionalidades mais bonitas com módulos de
terceiros. Estas são algumas das coisas fora do escopo do Node:
Web frameworks
Existe uma boa quantidade de web frameworks construidos em cima do Node (framework é
um pacote que tenta resolver um problema de alto nível e problemas similares ao modelar a
lógica de negócio), mas o Node não é um framework para web. Frameworks web são escritos
para serem utilizado no Node e nem sempre tomam o mesmo tipo de decisões sobre a adição
de complexidade, abstração e compreensão que o Node faz e podem ter outras prioridades.
Sintaxe da linguagem
O Node usa JavaScript e não muda nada sobre isso. Felix Geisendörfer tem um belo
conteúdo escrito sobre o ‘estilo de escrita do Node’ aqui.
Abstração da linguagem
Quando possível o Node vai usar a maneira mais simples de escrever algo. Código mais
‘bonito’ faz do seu JavaScript mais complexo e compromissado com vantagens e desvantagens.
Programar é difícil, especialmente em JS onde você tem 1000 soluções para o mesmo
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 60
problema! Essa é a principal razão para o Node optar pela simplicidade sempre que possível e
que pode ser uma opção universal. Se você está resolvendo um problema complexo e você
está insatisfeito com o modo que o Node implementa as coisas com soluções originais do JS,
sinta-se livre para resolver isso dentro do seu app ou módulo usando quaisquer abstrações que
você preferir.
Um grande exemplo de como o Node usa os callbacks. Logo no início foi experimentado a
caracteristica chamada ‘promessas’ que adiciona algumas funcionalidades para fazer o código
assíncrono parecer mais linear. Ele foi levado para o fora do núcleo do Node por algumas
razões:
eles são mais complexos que callbacks
ele podem ser implementados na userland (distriuído no npm como módulo de terceiros)
Considerando uma das mais universais e básicas ideias que o Node faz: ler um arquivo.
Quando você lê um arquivo e precisa saber onde os erros acontecem, como exemplo quando o
disco rígido morre no meio da sua leitura. Se você tem promessas tudo que você terá é um
código como esse:
fs.readFile('movie.mp4')
.then(function(data) {
// faça algo com os dados
})
.error(function(error) {
// lide com o erro
})
Isso adiciona uma complexidade, desnecessária. No lugar de duas funções separadas o Node
somente usa uma única função de callback. Aqui temos as regras:
Quando não existir erros passe null como primeiro argumento
Quando o existir erro, passar ele como primeiro argumento
O restante dos argumentos são usados para qualquer coisa (usualmente dados ou
respostas já que na maior parte do tempo o Node está lendo ou escrevendo coisas)
Por isso, o Node usa o estilo de callback:
fs.readFile('movie.mp4', function(err, data) {
// lide com o erro, e faça algo com os dados
})
Eventos em Node
No node com o módulo de eventos você pode disparar eventos, também chamando de
‘emissor de evento’, até mesmo o node usa em todas as suas APIs para emitir coisas.
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 61
Eventos são padrões comuns de programação, para conhecer melhor procure por ‘observer
pattern’ ou ‘pub/sub’ (publicar/assinar). Ao passo que callbacks são uma relação um-para-um
entre algo que espera pelo callback e outra parte que chama o callback, eventos seguem o
mesmo padrão com exceção de que eles são uma API de muitos-para-muitos.
Aqui temos casos comuns de uso dos eventos ao invés de simples callbacks:
Uma sala de chat onde você tem um canal de mensagens com muitos ouvintes.
Servidor de um jogo que necessita saber quando os players se ligam, desligam, movem-se,
atiram ou pulam
Conectores de bancos de dados podem precisar saber onde suas conexões estão abertar,
fechadas ou enviando um erro
Se você tentar escrever um servidor de chat que se conecte usando apenas callbacks ele irá
parecer com isso:
var chatClient = require('my-chat-client')
function onConnect() {
// exibe a UI quando conectar-se
}
function onConnectionError(error) {
// exibe erros para o usuario
}
function onDisconnect() {
// avisa ao usuario que ele foi desconectado
}
function onMessage(message) {
// exibe a mensagem na UI da sala
}
chatClient.connect(
'http://mychatserver.com',
onConnect,
onConnectionError,
onDisconnect,
onMessage
)
Como você pode ver é realmente pesado escrever porque você tem que passar todas as
funções em uma ordem especifica para a função .connect. Escrevendo isso com eventos irá se
parecer com isso:
var chatClient = require('my-chat-client').connect()
chatClient.on('connect', function() {
// exibe a UI quando conectar-se
})
chatClient.on('connectionError', function() {
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 62
// exibe erros para o usuario
})
chatClient.on('disconnect', function() {
// avisa ao usuario que ele foi desconectado
})
chatClient.on('message', function() {
// exibe a mensagem na UI da sala
})
Esta abordagem é bastante similar a utilização com callbacks-puros mas essa abordagem
introduz o método .on, onde é atrelado um callback ao evento. Isso significa que você escolhe
o que tem que estar assinado para chatClient. Você é capaz de assinar o mesmo evento várias
vezes com diferentes callbacks:
var chatClient = require('my-chat-client').connect()
chatClient.on('message', logMessage)
chatClient.on('message', storeMessage)
function logMessage(message) {
console.log(message)
}
function storeMessage(message) {
myDatabase.save(message)
Callbacks em Node
É um dos tópicos mais importantes para se entender se você tem que entender como
utilizar o node. Quase tudo no node usa callbacks. Eles não foram inventados para o node,
somente tem um uso particular com funções do JavaScript.
Callbacks são funções que serão executadas de modo assincrono, ou posteriormente. Ao
passo que o código for lido de cima para baixo de modo processual, programas assincronos
possivelmente executam funções em tempos diferentes baseado na ordem e velocidade em
que requisições http ou o trabalho de arquivamento do sistema acontecem.
A diferença pode ser confusa sendo determinada quando uma função é assincrona ou não
depende da execução de um grande contexto. Seque um simples exemplo de código
assincrono:
var myNumber = 1
function addOne() { myNumber++ } // define a função
addOne() // executa a função
console.log(myNumber) // mostra na saida padrão o numero 2
O código acima define uma função e na linha seguinte chama essa função, sem esperar por
nada. Onde ela é chamada imediatamente adicionando 1 a váriavel myNumber, então depois
que a função foi chamada você espera que o numero seja 2 na váriavel myNumber.
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de marçode 2016
Grupo SoftwareOriginSP
Página 63
Supondo que precisamos armazenar nosso numero em um arquivo chamado number.txt:
var fs = require('fs') // require é uma função especial do node para requisitar os módulos
var myNumber = undefined // não sabemos ainda qual valor esta armazenado no arquivo
function addOne() {
fs.readFile('./number.txt', function doneReading(err, fileContents) {
myNumber = parseInt(fileContents)
myNumber++
})
}
addOne()
console.log(myNumber) // mostra na saida padrão `undefined`
Porque é que temos undefined quando pedimos para mostrar o numero dessa vez? Nesse
código usamos o método fs.readFile, que acontece de módo assincrono. Usualmente você tem
que se comunicar com os discos rigidos ou redes bem de modo assincrono. Se for somente
para acesso a memória ou fazer algo na CPU isso é feito bem de modo sincrono. A razão pela
qual fazer o I/O assincrono é porque o acesso ao disco é 100,000 vezes mais devagar do que
comunicar-se com a memória (RAM).
Onde você executa um programa onde as funções são imediatamente definidas, mas não
executa elas imediatamente. Este é um conceito fundamental para entender sobre a
programação assincrona. Onde addOne é chamada fora de fs.readFile e move-se para a
proxima tarefa pronta para ser executada e não esperar o disco responder igual a fs.readFile.
Se não tem nada para executar o node espera por pendências de operações fs/network
terminarem ou pararem de executar saindo da linha de comando.
Onde fs.readFile esta completa para ler o arquivo (talves isso demore millisegundos ou
segundos e até mesmo minutos dependendo de quanto o disco é rápipdo) executando a
função doneReading e dando um erro (claro que se algum tipo de erro acontecer) e o
conteúdo do arquivo.
A razão pela qual undefined foi mostrado no código acima é que ele é chamado dentro de
console.log e fora de fs.readFile mostrando o valor anterior de myNumber e não o conteúdo
do arquivo.
Se você tem um pedaço de código que precisa ser executado várias e várias vezes ou um
tempo depois, o primeiro passo é colocar esse pedaço de código dentro de uma função. Aonde
você podera chamar sem precisar escrever ele em todas as partes que for necessário e
nomeando da meneira que fique claro aquilo que esta sendo feito. Isso ajuda a dar nomes
descritivos para as funções.
Callback são somente funções que são executadas de forma tardia. A chave para a
compreensão de callbacks é perceber que eles são utilizados quando você não sabe quando
alguma operação assincrona estará completa, mas você sabe quando se completará - a ultima
linha da função assincrona! A ordem de cima-para-baixo que você declara para callbacks isso
não é necessariamnete importante, somente a ordem lógica/hierárquica de assentamento do
código. Primeiro divida o código em funções e use callbacks para declarar se uma depende da
outra função para encerrar.
O método fs.readFile é fornecido pelo node no módulo fs, é assincrono e acontece quando
se tem um tempo curto para finalizar. Considerando o que ele faz: ele vai até o sistema
operacional, que por sua vez esta rodando em um disco rígido isso pode ou não estar girando a
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 64
milhares de rotações por minuto. Então ele tem que usar o lazer para ler os dados e enviar
atráves das camadas de comunição do sistema de volta para o seu programa em javascript.
Você da ao fs.readFile uma função (conhecida como callback) que sera chamada depois de
recuperar os dados do sistema de arquivos. Ela coloca os dados recuperados em uma variavel
do javascript e passa para sua função (callback) com essa variavél, neste caso a variavel se
chama fileContents porque ela contém o conteúdo do arquivo que foi lido.
Pense no restaurante do exemplo do tutorial lá do inicio. Em muitos restaurantes você pega
um número e coloca em sua mesa e espera por sua comida. Eles são como os callbacks. Isso
deixa claro para o servidor a quem chamar quando o cheeseburger estiver pronto.
Colocando console.log em uma função e passando ele para um callback.
var fs = require('fs')
var myNumber = undefined
function addOne(callback) {
fs.readFile('./number.txt', function doneReading(err, fileContents) {
myNumber = parseInt(fileContents)
myNumber++
callback()
}
}
function logMyNumber() {
console.log(myNumber)
}
addOne(logMyNumber)
Agora a função logMyNumber que é passada como argumento se torna a variavél callback
dentro da função addOne. Depois que fs.readFile terminar a variavél callback é chamada
(callback()). Somente funções podem ser chamadas, então se você passar qualquer outra coisa
diferente de uma uma função, causará um erro.
Onde uma função é chamada no javascript o código dentro dessa função é imediatamente
executado. Neste caso nosso log é executado onde callback é atualmente a função
logMyNumber. Lembre-se, somente se você definiu uma função não significa que ela será
executada. Você tem que chamar uma função para ela acontecer.
Para quebrar esse exemplo em mais pedaços, aqui tem uma linha do tempo de eventos que
acontecem quando o seu programa é executado:
1: o código é analisado, isso significa que se existir algum erro de sintaxe o pragrama
quebrará e será apontado aonde isso aconteceu.
2: addOne será chamado, onde logMyNumber será passado com uma função chamada
callback, que é o que precisa ser chamado quando addOne estiver completa.
Imediatamante disparando o método assincrono fs.readFile. Essa parte do programa leva
um tempo para terminar.
3: com nada para fazer, o node espera por um tempo até o fs.readFile encerrar a sua
execução.
4: fs.readFile termina e chama o callback, doneReading, que incrementa o numero e
imediatamente chama a função logMyNumber contida na variável callback.
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 65
Talves a parte mais confusa de se programar com callbacks é que as funções são somente
objetos armazenados em variáveis e passadas em todo o programa com diferentes nomes.
Dando nomes simples e descritivos para suas variáveis faz seu código ser mais legível para
outros. Geralmente falando em programas no node onde você enxerga uma variável como
callback ou cb você assume ela como uma função.
Você talves tenha escutado alguns termos como programação evencionada ou ciclo de
eventos. Onde é referenciado da mesma maneira que fs.readFile foi implementada. Node
primeiramente despacha a operação fs.readFile e espera por fs.readFile enviar um evento para
concluir. Equanto a resposta é esperada o node vai buscando checar outras coisas. Dentro do
node há uma lista de coisas a serem feitas mas não informaram ainda, então o ciclo do node
acaba e retorna para a lista várias vezes checando se o que estava sendo processado terminou.
Depois do termino ele pega o que foi ‘processado’, ex. callbacks que dependem desse termino
são chamados.
Aquie temos uma versão de um pseudocódigo do exemplo acima:
function addOne(thenRunThisFunction) {
waitAMinute(function waitedAMinute() {
thenRunThisFunction()
})
}
addOne(function thisGetsRunAfterAddOneFinishes() {})
Imagine que tenha 3 funções assincronas a, b e c. Para cada uma leva-se 1 minuto de
execução e depois de terminado elas chamam um callback (que é passado como primeiro
argumento). Se você tem que falar para o node ‘comece executando a, depois b depois que a
terminar, e executar c então b termina’ isso passa a ser:
a(function() {
b(function() {
c()
})
})
Onde esse código será executado,a é imediatamente executado, um minuto depois que ele
teminar e chama b, outro minuto depois que ele teminar e chamar c e finalmente depois que 3
minutos se passaram o node para de executar desde que não tenha mais nada para fazer. Isso
é definitivamente a maneira mais elegante para escrever o código acima, mas o ponto é esse,
se você tem esse código que espera por uma porção de código assincrono terminar, onde é
expressado essas dependencias colocando seu código em funções, isso é passado às outras
funções como callbacks.
A projeção do node requer que você pense de modo não-linear. Considerando essa lista de
operações:
ler um arquivo
processar um arquivo
Se você ingênuamente transforma-se isso em um pseudocódigo você teria este resultado:
var file = readFile()
processFile(file)
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 66
Esse tipo de linearidade no código (passo-a-passo, em ordem) não é o modo como o node
trabalha. Se esse código fosse executado onde readFile e processFile estão sendo chamados ao
mesmo tempo. Não faria o menor sentido porque readFile leva um tempo para completar sua
execução. Ao passo que você precisa expressar processFile que depende do readFile completo.
Esta a exata finalidade dos callbacks! E por causa da forma que o JavaScript trabalha você pode
escrever dependencias de diferentes maneiras:
var fs = require('fs')
fs.readFile('movie.mp4', finishedReading)
function finishedReading(error, movieData) {
if (error) return console.error(error)
// faça algo com os dados em movieData
}
Mas você támbem pode estruturar o código dessa maneira que irá funcionar:
var fs = require('fs')
function finishedReading(error, movieData) {
if (error) return console.error(error)
// faça algo com os dados em movieData
}
fs.readFile('movie.mp4', finishedReading)
Ou até mesmo assim:
var fs = require('fs')
fs.readFile('movie.mp4', function finishedReading(error, movieData) {
if (error) return console.error(error)
// faça algo com os dados em movieData
})
Depurando (Debugando) Node.js com o Depurador embutido.
Se a versão web do seu aplicativo está funcionando, porém a versão de linha de comando
está dando erro. O que está acontecendo de errado? Pode ser difícil de descobrir. Se a
aplicação simplesmente terminou sem imprimir nada. Seus try/catch e manipuladores de
evento não identificaram nenhum erro e a típica abordagem por console.log() não imprime
nada. Então o melhor a se fazer é usar o depurador do Node.js para fazer a depuração do seu
código. Uns até falam debugar o código, debugar é uma palavra derivada da palavra em Inglês
debugging (ou simplesmente debug).
O motor V8 da Google, onde o Node roda, vem com um extenso depurador acessível via
protocolo TCP e o Node.js tem um cliente embutido para este depurador. Este é considerado o
depurador (cliente de depuração) do Node. Este artigo ensina como usar o depurador do Node
para depurar seu script expondo como colocar pontos de interrupção (breakpoints), rodar o
REPL do Node no meio da depuração, percorrer pelo código e analizar as saídas do depurador.
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 67
O básico
O motor V8 da Google tem um depurador embutido e o Node tem um cliente para acessar
este depurador
O depurador pode ser iniciado usando executando o node com o argumento debug
Na sua aplicação você pode definir pontos de interrupção usando a palavra reservada
debugger
Você pode adicionar vigilantes para acompanhar o valor de expressões durante a
depuração
Agora vamos a cada etapa da debugação.
Inserindo alguns pontos de interrupção
Um ponto de interrupção (breakpoint) é um lugar em seu codigo onde você deseja que sua
aplicação pare momentaneamente para que você possa analisar o estado do seu programa
naquele ponto do código. Se você não usar um ponto de interrupção você vai ter percorrer o
código passo-a-passo até chegar onde você deseja depurar.
Então, basicamente, seu script você vai precisar colocar alguns pontos de interrupção em
lugares próximos onde você acha que o seu sistema esteja se comportando de maneira
indevida.
Iniciando o depurador
Para iniciar o depurador, rode seu script usando o argumento debug do node, no nosso
exemplo: node debug depurar.js. Você vai ser levado ao REPL do depurador debug > e então
você vai poder usar o comando help para ver a lista de comandos disponíveis e começar e
debugar seu código. Quando você abre o depurador seu inicia pausado na primeira linha e
você precisa usar o comando cont para rodar seu código até ser interrompido quando o
depurador encontrar a palavra reservada debugger ou você usar o comando pause.
$ node debug depurar.js
< debugger listening on port 5858
connecting... ok
break in /home/rafadev/git/depurador/depurar.js:1
1 x = 5;
2 setTimeout(function () {
3 debugger;
debug> cont
< Ola
break in /home/rafadev/git/depurador/depurar.js:3
1 x = 5;
2 setTimeout(function () {
3 debugger;
4 console.log("mundo");
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 68
5 }, 1000);
debug> next
break in /home/rafadev/git/depurador/depurar.js:4
2 setTimeout(function () {
3 debugger;
4 console.log("mundo");
5 }, 1000);
6 console.log("Ola");
debug> repl
Press Ctrl + C to leave debug repl
> x
5
> 2+2
4
debug> next
< mundo
break in /home/rafadev/git/depurador/depurar.js:5
3 debugger;
4 console.log("mundo");
5 }, 1000);
6 console.log("Ola");
7
debug> quit
O comando next avalia a próxima linha do seu código e o comando repl permite você
avaliar o estado atual do seu programa remotamente através do REPL do Node. Há também
outros comandos disponíveis, lembrando que você pode digitar help para lembrar dos
comandos disponíveis.
Vigilantes (Watchers)
Você pode vigiar o valor de uma expressão ou de uma variável enquanto depura seu código.
Em cada ponto de interrupção os vigilantes serão avaliados no contexto atual e seus valores
serão impressos logo depois da origem da interrupção.
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 69
Para começar a vigiar uma expressão, insira watch("sua_expressao"). O comando watchers
imprime os vigilantes ativos. Para deixar de vigiar uma expressão, insira
unwatch("sua_expressao").
Movimentação com next, step e out
O comando next, como já foi dito, prossegue a execução do programa avaliando a linha a
atual e pausando na primeira expressão da próxima linha. Caso a linha a ser avaliada faça
referência a algum método de outro módulo, ou até mesmo do core, você também pode
depurar o funcionamento interno deste método, basta utilizar a função step que é o
abreviamento para “step into this one” que pode ser traduzido para “entrar neste” que
basicamente entra para depurar o método internamente.
Quando você está depurando internamente o funcionamento deste método, você pode ir
utilizando os comandos next e step para rastrear com detalhes o que está ocorrendo “por trás
dos panos” depurando até o próprio core do Node, caso você deseje. Já o comando out serve
para você voltar para o código que chamou aquele método e pausar para a próxima expressão.
Lista de Comandos
Movimentação
cont, c - Continuar a execução
next,n - Próximo passo
step, s - Entrar
out, o - Sair
pause - Pausar a execução de um código (como o botão de pausar nas ferramentas de
desenvolvimento)
Pontos de interrupção
setBreakpoint(), sb() - Setar um ponto de interrupção na linha corrente
setBreakpoint(linha), sb(linha) - Setar um ponto de interrupção em uma linha específica
setBreakpoint('fn()'), sb(...) - Setar um ponto de interrupção na primeira instrução no corpo
da função
setBreakpoint('script.js', 1), sb(...) - Setar um ponto de interrupção na primeira linha do
script.js
clearBreakpoint, cb(...) - Remover um ponto de interrupção
Também é possível inserir um ponto de interrupção em um arquivo (módulo) que ainda não
foi carregado, por exemplo usando o comando setBreakpoint('mod.js', 23) adiciona um ponto
de interrupção no módulo mod.js na linha 23.
$ node debug main.js
< debugger listening on port 5858
connecting to port 5858... ok
break in /home/rafadev/git/depurador/main.js:1
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 70
1 var mod = require('./mod.js');
2 mod.hello();
3 mod.hello();
debug> setBreakpoint('mod.js', 23)
Warning: script 'mod.js' was not loaded yet.
1 var mod = require('./mod.js');
2 mod.hello();
3 mod.hello();
debug> c
break in /home/rafadev/git/depurador/mod.js:23
21
22 exports.hello = function() {
23 return 'hello from module';
24 };
25
debug>
Informação
backtrace, bt - Imprime um registro de chamadas do quadro atual de execução
list(5) - Lista o código fonte do script com 5 linhas de contexto (5 linhas antes e 5 depois)
watch(expr) - Adiciona uma expressão para a lista vigiada
unwatch(expr) - Remove uma expressão da lista vigiada
watchers - Lista todos os vigiados e seus valores (atumaticamente listado em cada ponto
de interrupção)
repl - Abre o REPL de debugação para avaliação no contexto de depuração do script
Controle de execução
run - Executa o script (é automaticamente executado quando o depurador é iniciado)
restart - Reinicia um script
kill - Mata um script
Diversos
scripts - Lista todos os scripts carregados
version - Imprime a versão da engine V8
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 71
Vantagens de uso
O depurador da V8 pode ser abilitado e acessado tanto iniciando o Node com o sinalizador
(flag) de linha de comando --debug como sinalizando um processo existente em Node com
SIGUSR1.
Uma vez que o processo foi colocado em modo de depuração dessa forma ele pode ser
conectado pelo depurador do node. Tanto conectado pelo pid quanto pelo URI para o
depurador. A sintaxe é:
node debug -p <pid> - Conecta com o processo via pid
node debug - conecta com o processo via URI tal como localhost:5858
Primeiros passos com Passport e Express em Node.js
Passport é um middleware para Node.js que faz a implementação de autenticação em um
aplicativo de maneira rápida e fácil. Em aplicações web modernas podem-se ter várias formas
de autenticação. Tradicionalmente usuários se logam fornecendo um usuário e uma senha.
Com o crescimento das redes socieais, logar-se com um provedor OAuth como o Facebook ou
o Twitter tem se tornado métodos populares de autenticação.
Passport reconhece que cada aplicação tem requisítos únicos de autenticação. Mecanismos
de autenticação, conhecidos como estratégias, são empacotados como módulos individuais. As
aplicações podem escolher qual estratégia empregar sem criar dependências desnecessárias.
Sabendo que muitos usuários preferem se logar utilizando uma já conta existente em uma
rede social, como o Facebook ou Twitter. Neste exemplo vai ser implementado o suporte para
o usuário se logar com a sua conta do Twitter.
Instalando as dependências
$ npm install express
$ npm install passport
$ npm install passport-twitter
$ npm install connect-ensure-login
O exemplo consiste em uma aplicação Express simples, baseada na aplicação desenvolvida
passo a passo do artigo anterior, então para melhor acompanhamento se certifique de ter
compreendido os conceitos básicos já apresentados.
Passport tem uma arquitetura modular que quebra o mecanismo de autenticação em
estratégias (neste caso do Twitter) que são distribuídas separadamente, mantendo o núcleo
leve. Também será usado o connect-ensure-login para proteger rotas exclusivas para usuários
logados.
Checklist da autenticação
São necessários verificar três itens para implementar a autenticação.
Configurar o middleware de sessão
Configurar as estratégias de autenticação
Adicionar as rotas de autenticação
Estes tópicos serão detalhados a seguir, começando por: rotas para o middleware.
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 72
Rotas para autenticação
Vamos adicionar rotas para /account, que mostra para a pessoa detalhes da conta.
app.get('/account',
ensureLoggedIn('/login'),
function(req, res) {
res.send('<html><body>Ola '+ req.user.username+'.<br/><a
href="/logout">Logout</a></body></html> ');
});
Para acessar esta página o usuário terá que estar logado, ensureLoggedIn vai verificar isso,
e caso ele não esteja logado, redireciona o usuário para a página de login. Que é
implementada a seguir.
app.get('/login',
function(req, res) {
res.send('<html><body><a href="/auth/twitter">Login com Twitter</a></body></html>');
});
Simples assim. O usuário pode clicar no link e se logar com sua conta do Twitter. O que nos
leva à próxima etapa da nossa implementação:
Configurar a autenticação do Twitter
A autenticação do Twitter usa o padrão de autorização OAuth, que significa que você vai
precisar obter uma chave (key) e uma chave secreta (secret) do Twitter. Se você não tem uma
ainda, você vai precisar registrar sua aplicação no Twitter. Para nosso que nosso exemplo
funcione em seu servidor local, você pode completar o campo Website com
http://127.0.0.1:3000/ e o campo Callback URL com
http://127.0.0.1:3000/auth/twitter/callback.
Uma vez que você tenha as chaves, configure a estratégia de autenticação do Twitter assim:
var TWITTER_CONSUMER_KEY = "INSIRA_SUA_KEY_AQUI";
var TWITTER_CONSUMER_SECRET = "INSIRA_SUA_SECRET_AQUI";
passport.use(new TwitterStrategy({
consumerKey: TWITTER_CONSUMER_KEY,
consumerSecret: TWITTER_CONSUMER_SECRET,
callbackURL: "http://127.0.0.1:3000/auth/twitter/callback"
},
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 73
function(token, tokenSecret, profile, done) {
// NOTA: Voce tera, provavelmente, que associar o usuario do Twitter
// com um registro do usuario no banco de dados da aplicacao.
var user = profile;
return done(null, user);
}
));
Esta função fornecida para a estratégia é conhecida como “callback de verificação”.
Callbacks de verificação recebem credenciais como argumentos (neste caso o token ,
tokenSecret e profile ), que são usados para localizar e retornar registros do usuário. A
instància user retornada vai ser definida no request em req.user para identificar o usuário
logado.
Na maioria das aplicações, você vai precisar associar a conta do Twitter com um registro do
usuário no banco de dados da aplicação. Isso permite, também, você associar outras contas
(como as do Facebook)no mesmo usuário, permitindo eles se logarem usando ambos os
serviços. Para manter este exemplo simples vai ser utilizado os dados do profile diretamente,
dispensando o uso de associações com o banco de dados.
O protocolo OAuth usado pelo Twitter envolve um processo de dois passos usando
redirecionamentos para a troca e verificação dos tokens. Isto é bastante complicado, mas o
middleware Passport faz esta tarefa fácil. Apenas adicione as seguintes rotas:
app.get('/auth/twitter', passport.authenticate('twitter'));
app.get('/auth/twitter/callback', passport.authenticate('twitter', { successReturnToOrRedirect:
'/account', failureRedirect: '/login' }));
A primeira rota vai começar a transação OAuth e redirecionar o usuário para o Twitter. Uma
vez logado, o Twitter vai redirecionar o usuário de volta para nossa aplicação e Passaport vai
trazê-lo de volta para a página original requisitada (ou /).
Fácil de mais, mas ainda há mais uma coisa a se fazer.
Configurando as sessões
A fim de manter usuário logado em nosso sistema, uma aplicação precisa implementar
suporte para sessões. Faça isso usando o cookie parser e o middleware de sessões embutidos
no Express, e inicializando o Passport.
app.use(express.static(__dirname + '/public'));
app.use(express.cookieParser());
app.use(express.session({ secret: 'usado para calcular o hash' }));
app.use(passport.initialize());
app.use(passport.session());
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 74
Quando o usuário se logar o registro do usuário é armazenado na sessão a fim de manter o
estado de logado enquanto ele nevega em seu site. Funções de serialização e deserialização
são fornecidas para controlar este processo.
passport.serializeUser(function(user, done) {
done(null, user);
});
passport.deserializeUser(function(obj, done) {
done(null, obj);
});
Como foi notado acima, se você está criando registros do usuário em seu próprio banco de
dados, você pode serializar somente o ID do usuário para minimizar a quantidade de dados
armazenados na sessão. Para manter este exemplo simples, todo o registro do usuário foi
serializado.
Rodando a aplicação
Para rodar nossa aplicação basta savá-la em um arquivo, neste exemplo chamado app.js e
executá-la passando o nome do arquivo como parâmetro para o node:
$ node app.js
Seridor Express iniciado na porta 3000
E para confirmar que tudo está funcionando você pode acessar a sua aplicação através de
seu navegador pelo endereço http://localhost:3000.
O código completo da aplicação
Abaixo segue o código completo da aplicação, basta copiar e colar em um arquivo
JavaScript, alterar as strings INSIRA_SUA_KEY_AQUI e INSIRA_SUA_SECRET_AQUI com os
dados do seu registro no Twitter e tudo funcionará corretamente.
var express = require('express'),
passport = require('passport'),
TwitterStrategy = require('passport-twitter').Strategy,
ensureLoggedIn = require('connect-ensure-login').ensureLoggedIn,
app = express();
app.use(express.static(__dirname + '/public'));
app.use(express.cookieParser());
app.use(express.session({ secret: 'usado para calcular o hash' }));
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 75
app.use(passport.initialize());
app.use(passport.session());
passport.serializeUser(function(user, done) {
done(null, user);
});
passport.deserializeUser(function(obj, done) {
done(null, obj);
});
var TWITTER_CONSUMER_KEY = "INSIRA_SUA_KEY_AQUI";
var TWITTER_CONSUMER_SECRET = "INSIRA_SUA_SECRET_AQUI";
passport.use(new TwitterStrategy({
consumerKey: TWITTER_CONSUMER_KEY,
consumerSecret: TWITTER_CONSUMER_SECRET,
callbackURL: "http://127.0.0.1:3000/auth/twitter/callback"
},
function(token, tokenSecret, profile, done) {
// NOTA: Voce tera, provavelmente, que associar o usuario do Twitter
// com um registro do usuario no seu banco de dados.
var user = profile;
return done(null, user);
}
));
app.get('/', function(req, res){
res.send('<html><body>Ola mundo<br/><a href="/login">Login</a></body></html>');
});
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 76
app.get('/account',
ensureLoggedIn('/login'),
function(req, res) {
res.send('<html><body>Ola '+ req.user.username+'.<br/><a
href="/logout">Logout</a></body></html> ');
});
app.get('/login',
function(req, res) {
res.send('<html><body><a href="/auth/twitter">Login com Twitter</a></body></html>');
});
app.get('/logout',
function(req, res) {
req.logout();
res.redirect('/');
});
app.get('/auth/twitter', passport.authenticate('twitter'));
app.get('/auth/twitter/callback', passport.authenticate('twitter', { successReturnToOrRedirect:
'/account', failureRedirect: '/login' }));
var server = app.listen(3000);
console.log('Seridor express iniciado na porta %s', server.address().port);
Como funciona a função require do Node.js
O Node.js segue a CommonJS, uma especificação de ecossistemas para o JavaScript, e a
função embutida require é a maneira mais fácil de incluir módulos existentes em arquivos
separados. O funcionamento básico do require é que ele lê o arquivo JavaScript, interpreta o
script e em seguida retorna o conteúdo do objeto exports. Segue um exemplo de módulo para
melhor compreensão:
console.log("Avaliando o exemplo.js");
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 77
var invisivel = function () {
console.log("invisivel");
}
exports.mensagem = "Oi";
exports.falar = function () {
console.log(exports.mensagem);
}
Podemos testar nosso módulo rodando através do REPL do node. Se formos na pasta onde
salvamos nosso projeto exemplo.js com o prompt e abrirmos o REPL do node, para isso basta
digitar node sem passar nenhum arquivo como parâmetro e ele abrirá em modo REPL, em
seguida basta digitar require("./exemplo.js") para importar nosso módulo. Teremos a seguinte
saída impressa:
> require("./exemplo.js")
Avaliando o exemplo.js
{ mensagem: 'Oi', falar: [Function] }
Aqui é possível ver que o módulo foi importado com sucesso, e como foi dito a função
require primeiro interpretou o script, imprimindo Avaliando o exemplo.js na primeira linha, e
em seguida retornando o conteúdo do objeto exports , que contém apenas dois objetos {
mensagem: 'Oi', falar: [Function] } . A função invisivel não foi importada pois não foi atribuída
ao objeto exports .
Porém caso quisermos utilizar a função falar de nosso módulo veremos que ela não estará
disponível no contexto global, e a mensagem de erro dirá que falar não está definida.
Para que seja possível utilizar as funções importadas de um módulo temos que importá-lo e
atribuir o retorno da função require à uma variável. Se rodarmos no REPL o código var
exemplo = require('./exemplo.js') ocorrerá que agora nosso script exemplo.js será avaliado e
o objeto exemplo receberá { mensagem: 'Oi', falar: [Function] } , que é o retorno da função,
assim é possível facilmente acessar sua função falar . Acompanhe o exemplo:
> exemplo = require("./exemplo.js")
Avaliando o exemplo.js
{ mensagem: 'Oi', falar:[Function] }
> exemplo.falar()
Oi
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 78
undefined
Pode ser que em seu console não apareça a mensagem Avaliando o exemplo.js novamente,
você seberá o motivo mais adiante.
Se você quiser atribuir uma função ou um novo objeto para exports , então você terá que
usar o objeto module.exports . Veja o exemplo do código exemplo2.js para compreender
melhor.
module.exports = function () {
console.log("Ola mundo")
}
require('./exemplo2.js')()
Neste exemplo ao importar o módulo com require , primeiramente ele interpreta (avalia,
executa) o código o que faz o módulo importar e chamar a sí próprio e ao final require retorna
a função atribuida ao exports . Ao importar o módulo temos a saída esperada:
> require('./exemplo2.js')
Ola mundo
[Function]
A última linha [Function] confirma que o valor de retorno da chamada
require('./exemplo2.js') é uma função e a linha Ola mundo confirma que o código foi
interpretado antes de ser retornada esta função.
É importante dizer, também, que o código é interpretado apenas na primeira vez que ele é
importado, se você importá-lo mais de uma vez a função require irá reutilziar o objeto
exports que já está em salvo cache. Para ilustrar este ponto acompanhe o exemplo abaixo:
> require("./exemplo.js")
Avaliando o exemplo.js
{ mensagem: 'Oi', falar: [Function] }
> require("./exemplo.js")
{ mensagem: 'Oi', falar: [Function] }
> require("./exemplo.js").mensagem = "Ola"
'Ola'
> require("./exemplo.js")
{ mensagem: 'Ola', falar: [Function] }
> require("./exemplo.js").falar()
Ola
undefined
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 79
Como pode ser visto no exemplo, exemplo.js é interpretado apenas na primeira vez e todas
as chamadas posteriores à require() só invoca o módulo salvo em cache, em vez de ler o
arquivo novamente. No exemplo é possível ver que isso pode causar efeitos colaterais caso
utilizado indevidamente.
As regras que o require usa para buscar os arquivos pode ser um pouco complexa, mas uma
regra de ouro é que se o arquivo não inicia com ./ ou /, então ele é considerado um módulo do
core e o endereço local do Node é verificado, ou uma dependência na pasta local
node_modules. Se o arquivo começa com ./ então ele é considerado um arquivo relativo com
o arquivo que chamou o require. Se o arquivo começa com / então ele é considerado
pertencente ao endereço absoluto.
Observação: - Você pode omitir o .js, o require vai automáticamente adicioná-lo caso for
necessário. - Se o nome do arquivo passado para require é o nome de um diretório, a função
vai primeiramente buscar por package.json no diretório e então carregar o arquivo
referenciado na propriedade main. Caso contrário a função irá procurar por um arquivo
chamado index.js dentro da pasta.
Para informações mais detalhadas veja o artigo detalhado sobre módulos em Node.js.
Como usar o REPL do Node.js
O Node.js vem com um REPL (Read-Eval-Print Loop), que é um programa simples e
interativo que lê expressões ou trechos de programa, avalia (ou executa) e imprime o
resultado. Este é o consolo do Node.js e qualquer código JavaScript válido que pode ser escrito
em um script pode ser passado para o REPL. Ele pode ser extremamente útil para
experimentar o Node.js, debugar códgio, e descobrir alguns dos comportamentos mais
excêntricos do JavaScript.
Para rodar é simples, basta rodar o node no console sem inserir um nome de arquivo na
frente: node. Lembrando que para rodar um servidor node você teria que passar o arquivo do
servidor como parâmetro, por exemplo: node servidor.js.
Executando o node usando o comando node leva você para um simples console > onde você
pode escrever qualquer comando JavaScript que desejar. Como na maioria dos prompts você
pode usar as setas para cima e para baixo para pelo seu histórico de comandos e modificar
comandos anteriores. No REPL você também pode usar a tecla Tab para fazer o REPL tentar
auto-completar o comando.
Sempre que você digitar um comando o REPL vai imprimir o valor de retorno do comando.
Se você quer reusar o resultado do comando anterior você pode usar a variável especial _.
Por exemplo:
node
> 1+1
2
> _+1
3
Uma coisa importante para observar é onde os valores de retorno do REPL estão interessados:
> x = 10
10
> var y = 5
> x
10
> y
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 80
5
Quando a palavra-chave var não é usada o valor da expressão é armazenado e retornado.
Quando a palavra-chave var é usada o valor da expressão é armazenado, mas não retornado.
Se você precisa acessar qualquer módulo embutido, ou qualquer módulo de terceiros, ele
pode ser acessado com a função require, assim como é feito num script Node.
node
> path = require('path')
{ resolve: [Function],
normalize: [Function],
join: [Function],
dirname: [Function],
basename: [Function],
extname: [Function],
exists: [Function],
existsSync: [Function] }
> path.basename("/a/b/c.txt")
'c.txt'
Note novamente que sem a palavra-chave var, o conteúdo do objeto é retornado
imediatamente e imprimido no stdout.
O node possui alguns módulos embutidos, como o módulo console que contém funções
úteis e pode ser usado sem precisar ser importado. Ao se digitar console no REPL do node ele
retorna todas as funções públicas deste módulo.
> console
{ log: [Function],
info: [Function],
warn: [Function],
error: [Function],
dir: [Function],
time: [Function],
timeEnd: [Function],
trace: [Function],
assert: [Function] }
E ao se utilizar a função log deste módulo nós temos:
> console.log("Imprima este texto")
Imprima este texto
undefined
É interessante observar que o texto foi impresso no console, conforme o esperado, porém a
função console.log("Imprima este texto") não tem valor de retorno, e por isso o REPL imprime
undefined na linha seguinte.
Com Node é fácil construir programas de rede escalonáveis
No exemplo do servidor web “Olá Mundo” apresentado abaixo, muitas conexões de clientes
podem ser tratadas simultaneamente. Node diz ao sistema operacional (através de epoll,
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 81
kqueue, /dev/poll ou select) que ele deve ser notificado quando uma nova conexão é feita, e
então ele volta a dormir quando completa o processamento. Se alguém se conecta no
servidor, então o node executa a função de retorno (callback function) programada e cada
conexão é se torna apenas uma pequena alocação de heap.
var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Olá Mundo\n');
}).listen(1337, "127.0.0.1");
console.log('Servidor rodando em http://127.0.0.1:1337/');
Isto está em contraste com o modelo de concorrência mais comum utilizado hoje em dia,
onde threads do Sistema Operacional são empregadas para tratar as conexões. Sistemas de
rede baseados em thread são relativamente ineficiente e muito difíceis de usar. Para entender
melhor leia os artigos (em Inglês): The C10K problem e Scalable Network Programming. Node
vai apresentar muito mais eficiência na utilização da memória sob altas cargas do que sistemas
que alocam pilhas de threads com 2mb para cada conexão. Além disso, os usuáriosdo Node
estão livres de preocupações com processos em deadlock - não há bloqueios. Quase nenhuma
função em Node executa diretamente E/S, então o processo nunca bloqueia. Porque nada
bloqueia, programadores menos experientes são capazes de desenvolver sistemas eficiêntes.
Node é semelhante em design e foi influenciado por sistemas como a Máquina de eventos
do Ruby e o Twisted do Python. Node leva o modelo de eventos um pouco mais a diante - ele
apresenta um laço de eventos como controle de fluxo (control flow) nativo, em vez de uma
biblioteca. Em outros sistema sempre existe uma chamada bloqueante para iniciar o laço de
eventos (event-loop), neles normalmente é definido o comprotamento através de callbacks no
início do script e no final do script inicia-se o servidor através de uma chamada bloqueante
como EventMachine::run(). No Node não há tal chamada para iniciar o laço de eventos, Node
simplesmente entra no laço de eventos após executar o script de entrada e só sai do laço de
eventos quando não há mais funções de retorno para serem executadas. Este comportamento
é como acontece com o JavaScript do navegador - o laço de eventos é invisível ao usuário.
O protocolo HTTP é de primeira classe em Node. A biblioteca HTTP do Node nasceu das
experiências do autor em desenvolvimento e trabalhando com servidores web. Por exemplo, o
stream de dados para a maioria dos frameworks web é impossível. O Node tenta corrigir este
problema com seu parser HTTP e sua API. Juntamente com a infra-estrutura puramente
orientada a eventos de Node, ele faz uma boa base para bibliotecas web ou frameworks.
Mas o que ocorre com a concorrência em múltiplos processadores? Threads não são
necessárias para escalonar programas para computadores multi-cores? No Node você pode
iniciar um novo processo usando child_process.fork() e este processo vai ser processado em
paralelo e para o balanciamento de carga de novas conexões através de múltiplos processos é
utilizado o módulo cluster.
Funções temporizadoras embutidas no JavaScript? setTimeout e setInterval
Em JavaScript existem duas funções temporizadoras embutidas (built-in timer functions),
setTimeout e setInterval que podem ser usadas para chamar funções de retorno (callback
functions) após um determinado tempo. Veja um exemplo de uso abaixo:
setTimeout(function() { console.log("setTimeout: Ja passou 1 segundo!"); }, 1000);
setInterval(function() { console.log("setInterval: Ja passou 1 segundo!"); }, 1000);
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 82
Este código imprime a seguinte saída:
setTimeout: Ja passou 1 segundo!
setInterval: Ja passou 1 segundo!
setInterval: Ja passou 1 segundo!
setInterval: Ja passou 1 segundo!
setInterval: Ja passou 1 segundo!
...
Você pode ver que os parâmetros são os mesmos para as duas funções. O segundo
parâmetro é um número que diz quanto tempo de espera, em milisegundos, vai passar antes
de chamar a função passada como primeiro parâmetro. A diferença entre as duas funções é
que setTimeout chama a função passada apenas uma vez, enquanto setInterval vai chamar a
função passada indefinidamente sempre no intervalo de tempo passado.
Você vai poder perceber que o laço de eventos(event loop) do Node vai sempre tentar
chamar sua função no tempo pré-determinado por você, porém ele nem sempre vai acertar
com precisão milimétrica, pois como o Node roda em apenas uma thread e seu contexto pode
estar processando outra função no momento que ele deveria chamar sua função e ele vai
precisar processar esta função até o final antes de chamar a próxima função do laço de
eventos (event loop). Por isso é muito importante que você sempre escreva funções não
bloqueantes para sua aplicação em Node, assim você estará aproveitando todas as vantagens
do Node.
Você deve ficar atento com a função setInterval porque ela pode causar alguns efeitos
indesejados. Se, por exemplo, você precisar se certificar que seu servidor está rodando
pingando ele todo segundo, você pode pensar em fazer algo assim:
var recursiva = function () {
console.log("Se passaram 1 segundo!");
setTimeout(recursiva,1000);
}
recursiva();
Como você pode ver este código chama a função recursiva que, quando processada, faz
uma chamada para setTimeout(recursiva,1000); que chama recursiva de novo após 1 segundo,
tendo assim quase o mesmo efeito de setInterval enquanto permanece mais resistente à erros
não intencionais que podem ocorrer.
Você também pode limpar os temporizadores com clearTimeout e clearInterval. O uso
destas
funções é bem simples:
function nunca_chamada () {
console.log("Voce nao deve executar esta funcao!");
}
var timeout1 = setTimeout(nunca_chamada,1000);
var interval1 = setInterval(nunca_chamada,1000);
clearTimeout(timeout1);
clearInterval(interval1);
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 83
Como pode ser visto no código, se você guardar os valores de retorno dos temporizadores,
você poderá facilmente desativá-los usando clearTimeout e clearInterval. O código assima não
imprime nada no console pois os temporizadores são limpos antes que possam executar a
função de retorno.
O segredo final para as funções temporizadoras é que você pode passar parâmetros para a
função de retorno (callback function) que será chamada apenas adicionando mais parâmetros
para setTiemout e setInterval:
setTimeout(console.log, 1000, "Esta funcao", "tem", 4, "parametros");
setInterval(console.log, 1000, "Esta funcao so tem um parametro");
O código acima imprime o seguinte retorno no console:
Esta funcao tem 4 parametros
Esta funcao so tem um parametro
Esta funcao so tem um parametro
Esta funcao so tem um parametro
Esta funcao so tem um parametro
...
Com estas funções temporizadores do JavaScript você pode facilmente executar tarefas de
em segundo plano (background tasks) no seu servidor Node e o laço de eventos do Node vai
cuidar de tudo muito bem.
NPM, The Node Package Manager
Olá pessoal! Este é o meu primeiro post aqui na comunidade NodeBR, e o assunto hoje será
sobre o NPM (Node Package Manager).
Apartir da versão Node.js 0.5.x que o NPM passou a ser integrado ao instalador do Node.js e
isso simplificou a vida dos desenvolvedores, pois antes disso existia diversos gerenciadores de
pacotes para o Node.js.
Ele também mantém um repositório online NPM que também é mantido pela Joyent,
atualmente ele contém mais de 30 mil módulos open-source!
O objetivo desse post é apresentar os principais comandos para você gerenciar trabalhar com
ele.
Conhecendo os principais comandos
npm install nome_do_módulo - instala um módulo no projeto.
npm install nome_do_módulo –save - instala o módulo e adiciona-o na lista de
dependências do package.json do projeto.
npm list - lista todos os módulos existentes no projeto.
npm list -g - lista todos os módulos globais.
npm remove nome_do_módulo - desinstala um módulo do projeto.
npm update nome_do_módulo - atualiza a versão do módulo.
npm -v - exibe a versão atual do npm.
npm adduser nome_do_usuário - cria um usuário no site NPM para publicar seu módulo na
internet.
npm whoami - exibe detalhes do seu perfil público do npm (é necessário criar um usuário
com o comando anterior).
npm publish - publica o seu módulo, é necessário ter uma conta ativa no NPM.
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 84
Subindo o node com express e entregando conteúdo dinâmico
Este postvai ensinar como subir um aplicação Node utilizando o express, um framework web
para Node, e também vai falar um pouco do package.json que guarda as informações de
metadados do nosso projeto.
Primeiramente crie a estrutura de diretórios, que nos será útil durante o desenvolvimento do
aplicativo.
/
/static
/static/css
/static/css/style.css
/static/javascript
/static/javascript/app.js
/views
/views/index.html
/package.json
/myapp.js
Definindo o projeto ‘package.json’
Precisamos criar o arquivo package.json de metadados de informações na raiz do projeto.
Esse arquivo guarda informações do projeto e suas dependencias. Com ele fica fácil fazer
deploy e o controle de dependência. o ideal é deixa o arquivo mais limpo possível.
{ "name": "server-web",
"version": "0.4.0",
"description": " Servidor http",
"contributors": [ {
"name": "Onezino Gabriel Moreira",
"email": "heat2k4@hotmail.com" } ],
"keywords": [ "cli", "http", "server" ],
"dependencies" : {
"express" : "3.x",
"consolidate" : "0.4.x",
"swig": "0.12.x" }
}
As dependências que usamos são o renderizador de template e o framework web express.
Pra instalar todas as dependências de uma vez é so digitar o comando na raiz do projeto que a
ferramenta de pacote de módulos do node (NPM) se encarregará de todo o trabalho:
npm install
Escrevendo sua aplicação
O próximo passo é escreve nossa aplicação, no myapp.js, a começar carregando os módulo
que precissamos.
var express = require('express');
var cons = require('consolidate');
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 85
De novidade temos o consolidate, que é um renderizador de template, tepois temos o
express que é nosso objeto de estudo deste post. O express faz nosso wrapper com a
biblioteca http então não precisamos carrega-las expressamente.
app = express();
app.get('/',function(req,res){
res.send('Hello world!')});
app.listen(3000);
console.log('app rodando na prota 3000');
A novidade está na forma de tratar o response, onde só precisamos chamar o método send.
Mas isso não é muito útil, então vamos registrar nosso renderizador e entregar uma página
mais elegante ao usuário.
app.engine('html', cons.swig);
app.set('view engine','html');
app.set('views',__dirname+'/views');
Nesse trecho dizemos ao express quem vai renderizar nossas páginas e a localização dos
tempaltes. O express aceita uma lista grande de templates, no nosso exemplo estou utilizando
o consolidate mas fique livre para utilizar qualquer um de sua preferência. E editamos a linha
que entrega o conteúdo na rota /.
/* app.get('/',function(req,res){res.send();}); */
app.get('/',function(req,res){
res.render('index')});
Pronto, agora só precisamos servir os arquivos estáticos (js, css, imagens). Utilizamos um
middleware para tratar as chamadas que trata as chamadas get ao arquivos pesquisando de
forma encadeada.
app.use(express.static(__dirname + '/static'));
Podemos agorar utilizar os arquivos /css/style.csse /javascript/app.js em nosso html. Você
também pode prefixar o caminho dos arquivos estáticos. vamos utilziar o prefixo /js para
nossos arquivos javascript.
app.use('/js',
express.static(__dirname+'/static/javascript'));
Pronto o javascript pode ser utilizado apartir do caminho /js, exemplo /js/app.js.
Conclusão
Fizemos um setup básico para uma aplicação rodando em express. Essa foi uma um post de
introdução funcional, outros posts irão explorar melhor as características do express e vão
mostrar como este framework se comporta com aplicações mais elaboradas.
Utilizando módulos em sua aplicação Node.js
Pessoal, vamos trabalhar com módulos em nossa aplicação Node. Vou começar com o
código abaixo.
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 86
http = require('http');
Essa instrução carrega o módulo http, um módulo do sistema core module. O carregamento
de módulos em Node é feito pela função require. Para quem vem do Python é como executar
o código:
import os as real_os
Módulos são sub programas que executão tarefas bem definidas. Nós esperamos com nosso
exemplo que o módulo http permita que utilizemos os protocolo http. Os módulos do sistema
do Node têm suas funções documentadas na página da API do Node.
Core Module
São módulos embutidos no Node. Eles são carregados pela declaração sem prefixo do nome
do módulo. Por exemplo:
require('buffer');
Módulos declarados dessa forma dão preferência aos módulos do sistema, mesmo tendo
um arquivo buffer.js na raiz de nossa aplicação.
Módulos da aplicação.
É comum uma grande aplicação dividir suas tarefas em módulos para atender aos requisitos
do sistema, tomando como exemplo uma aplicação com o arquivo circle.js (expõe funções
matemáticas aplicadas a círculos) em sua raiz. Esse arquivo corresponde a um módulo da
aplicação e pode ser chamado da seguinte forma:
circle = require('./circle');
circle = require('circle');
circle = require('/path/to/app/circle');
todas são formas válidas de carregar módulos na aplicação.
Prefixos ./ /
Os prefixos determinam a localização do módulo. O prefíxo / utiliza o caminho absoluto do
módulo, já o prefíxo ./ utiliza o caminho relativo a partir do caminho atual.
Dica: Quando o módulo não vem prefixado e há um conflito de nomes com módulos do
sistema, os módulos do sistema ganham preferência no carregamento.
Extensão dos módulos
Quando os módulos não tem a extensão explícita o Node procura pelas seguintes extensões
em sua devida ordem :
Primeiro .js: o arquivo é iterpretado como um arquivo de código fonte javascript;
Depois .json: é utilizado um analisador JSON no arquivo;
Por último .node: interpretado como um addon através do dlopen.
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 87
Módulos do node_module
Quando o arquivo não é prefixado e não é nativo do Node core modules, o Node busca o
módulo na pasta node_module. A busca percorre toda o caminho de diretórios do código
executado até a raíz.
Fica mais fácil de entender com o exemplo abaixo. (vamos supor que código é executado
em /path/to/app/code.js)
require('mymodule');
Como mymodule não é um módulo do sistema ele então pesquisa na pastas node_module.
Essa pesquisa é recursiva por todo o caminho iniciando no diretório atual até atingir a raiz.
1º /path/to/app/node_modules/mymodule.js
2º /path/to/node_modules/mymodule.js
3º /path/node_modules/mymodule.js
4º /node_modules/mymodule.js
Diretórios como módulos
Quando um diretório da aplicação contém um arquivo package.json ele é também é
considerado um módulo e pode ser carregado como outros módulos.
draw = require('./draw');
Ele busca pelo arquivo: ./draw/package.json que contém informações do módulo e qual
arquivo carregar. Caso não exista esse arquivo mas exista um index.js ele é utilizado como
arquivo source do módulo.
Outras informações que você deve conhecer sobre os módulos
Os módulos são carregados apenas uma vez.
Node trata as chamadas cíclicas de módulos, então mesmo que não seja muito bom tê-las
você não precisa se preocupar.
Somente variáveis exportadas estão disponíveis no módulo, as demais variáveis e funções
são privadas do módulo.
Você pode carregar somente atributos específicos do módulo. Ex: var EventEmitter =
require('events').EventEmitter;
Cuidado coma armadilha do escopo de variáveis em JavaScript
JavaScript pode parecer sintaticamente parecido com linguagens c-like, mas seu
comportamento com relação ao escopo das variáveis funciona bem diferente do que estamos
acostumados.
O javascript trabalha com o conceito de contexto de execução, chamando normalmente de
contexto. O contexto define o escopo das variáveis ou funções.
O contexto mais externo é conhecido como contexto global (global context) e é
representado por um objeto. Ele é diferente para cada ambiente de execução do javascript. O
global context de um browser é o objeto window, para o node.js ele é acessível através do
GLOBAL ou GLOBAL.window ( forma mais parecida com a dos browser). Toda variável ou
função global é então um atributo desse objeto. Quando um contexto é finalizado ele remove
todos os objetos que pertencem a ele.
Cada função tem seu próprio contexto de execução. Quando uma função é chamada seu
contexto é incluído na pilha de execução, e removido quando a função termina sua execução
retornando ao contexto anterior ao da função.
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 88
Pesquisa do indentificador
A cada execução de um contexto é criado uma “encadeamento de contexto” dos objetos na
memória para permitir o acesso a todas as variáveis e funções que o contexto tem acesso. As
declarações de funções e variáveis do contexto atual são os primeiros objetos que fazem parte
dessa cadeia, os contextos encadeados começam dos mais próximos para os mais distantes na
pilha de contextos. A pesquisa pelo identificado percorre essa cadeia de contexto. A procura
sempre ocorre do início da cadeia para o final até ele ser encontrado ou chegar ao ultimo
contexto(global context).
Trabalhando com with e try catch.
O uso dessas expressões criam uma camada a mais no encadeamento de contexto. Com o
with é criado uma camada de objetos com todos os atributos do objeto que está se
trabalhando, e quando o catch é executado um objeto é incluído dando acesso a exceção
jogada.
function() { with(location) { var url = href + “?run=1”; } return url; }
Blocos sem escopo
Essa é com certeza a maior diferença entre javascript e as outras linguagens. No javascript
blocos de código não criam um contexto próprio de execução permanecendo no contexto em
que o o bloco foi executado.
if(true) { var nome = “gabriel”; } alert(nome); // gabriel
ou ainda mais confuso
for(i= 0;i<10;i++) { /*codigo */ } alert(i); // 10
Os programadores também tem que tomar cuidado quanto a declaração de variáveis. Se
esquecer de utilizar o var a variável é incluída no contexto global e não no contexto de
execução atual.
function f() { var a = 10; b = 20; return a + b; }
alert(f()); //30
alert(b); //20
alert(typeof a); //undefined
Referências: - javascript - node.js global variables? - Stack Overflow - Professional Javascript for
web developer
Passando função como parâmetro no JavaScript com Node.js
Antes de tentar entender o funcionamento do Node.js temos que compreender uma
característica do JavaScript herdada da programação funcional. No JavaScript você pode, por
exemplo, passar uma função como parâmetro. Vamos ver alguns exemplos práticos para ver
como isso funciona na prática.
Podemos fazer alguma coisa como isso no JavaScript:
function falar(palavra) {
console.log(palavra);
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 89
}
function executar(funcao, valor) {
funcao(valor);
}
executar(falar, "Oi JavaScript!");
Se executarmos nosso código vamos receber a saída impressa no console Oi JavaScript!.
Você pode testar este exemplo utilizando seu prompt de comando. O Node.js é um ambiente
de execução para usar o JavaScript fora do navegador também! Você pode acessar digitando o
comando node no seu console e inicia o console interativo REPL, como no exemplo:
> function falar(palavra) {
... console.log(palavra);
...}
undefined
> function executar(funcao, valor){
... funcao(valor);
... }
undefined
> executar(falar, "Oi JavaScript!");
Oi JavaScript!
undefined
E o nosso console imprimiu a saída esperada: Oi JavaScript!
Vamos entender o que está acontecendo neste contexto. O que fizemos aqui foi passar a
função falar como o primeiro parâmetro da função executar. Isso é bem diferente de passar o
valor retornado return pela função falar. A função falar, então, se tornou uma variável de
nome funcao dentro da função executar, e executar pode chamar a função contida na variável
adicionando os parênteses na variável: funcao().
E o que são estes undefined no console? Para cada comando dado no console do Node na
linha seguinte é impresso o valor retornado return deste comando. Vamos analisar com calma:
o primeiro comando foi definir a função falar, após a definição retornou undefined, o segundo
comando foi definir a função executar, que também retornou undefined, o terceiro comando
que executou a função executar, que executou a função falar contida na variável funcao, que
acabou por executar a função console.log que imprime no console uma string, mas a função
executar em si não tem nenhum valor de retorno, então retornou undefined.
Nós podemos passar uma função como parâmetro para outra função usando seu nome,
como foi visto no exemplo. Após entender este conceito veremos no exemplo a seguir que
esta é a maneira indireta de se fazer isso, nós não precisamos definir a função para depois
passar ela como parâmetro, nós podemos definir e passar a função como parâmetro para
outra função no mesmo lugar.
function executar(funcao, valor) {
funcao(valor);
}
executar( function(palavra) { console.log(palavra) }, "Oi JavaScript!");
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 90
Neste exemplo nós definimos a função que nós queremos passar para executar no lugar
onde a função espera receber seu primeiro parâmetro. Aqui nós não precisamos nem dar um
nome à função passada, por isso esta função é chamada de função anônima.
Com estes exemplos podemos observar que no JavaScript é possível passar uma função
como parâmetro quando chamamos outra função, e podemos fazer isso atribuindo nossa
função à uma variável que pode ser passada, ou simplesmente definindo nossa função bem
onde estamos chamando a função que vai recebê-la como parâmetro, usando uma função
anônima.
Exemplo Hello World em Node.js
Este é um programa rápido para garantir que tudo está instalado e funcionando
corretamente:
var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello Node.JS!');
}).listen(8080);
console.log('Server running at http://localhost:8080/');
Rode o código com o comando de linha do Node em seu prompt de comando:
> node hello_node.js
Server running at http://localhost:8080/
Agora quando você acessar o endereço http://localhost:8080/ com seu navegador você ler
um caloroso Hello Node.JS !
Parabéns você instalou o Node.js com sucesso e está pronto para mergulhar nos nós
assíncronos do Node.
JavaScript no servidor com Node.js
A primeira encarnação do JavaScript viveu no navegador. Mas este é o contexto. Isso define
o que você pode fazer com a linguagem, mas isso não fala muito sobre o que a linguagem em
si pode fazer. JavaScript é uma linguagem completa: você pode usar isso em muitos contextos
e fazer de tudo, com isso você pode alcançar o que as outras linguagens consegue.
Node.jsé realmente só mais um contexto: isso permite você rodar código JavaScript em
backend, fora do navegador.
A fim de executar o JavaScript que você pretende rodar em backend, ele precisa ser
interpretado e executado. Isso é o que Node.js faz, fazendo uso da Máquina Virtual V8 da
Google, o mesmo ambiente de execução do JavaScript usado pelo Google Chrome.
Além disso, Node.js vem com muitos módulos úteis, então você não precisa escrever tudo
do começo, por exemplo alguma função que escreva uma string no console.
Portanto, Node.js é de fato duas coisas: um ambiente de execução e uma biblioteca.
Você pode aprofundar-se cada vez mais neste mundo e descobrir como é fácil e divertido
desenvolver aplicações altamente escaláveis em JavaScript com Node. O primeiro passo é
instalar o Node e a maneira mais fácil de conseguir isso é instalando o Node.js através do
gerenciador de pacotes, porém você também vai poder instalar o Node.js através do GitHub.
Feito isso, desenvolva sua primeira aplicação, com apenas 6 linhas de código, através do
Exemplo Hello World em Node.js. Você perceberá como é fácil e divertido o desenvolvimento
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 91
com JavaScript no servidor e não só isso, ele também é altamente eficiênte e escalável por ser
um servidor orientado a eventos não bloqueante.
Caso você queira conhecer mais sobre eventos e como desenvolver aplicações orientadas a
eventos, você pode ler o artigo explicando eventos em Node que poderá te ensinar muito
sobre eventos.
É claro que tem muito mais a ser descoberto no Node e o objetivo deste artigo é te dar
apenas o gostinho bom do prazer de desenvolver em Node, não deixe de acompanhar as
comunidades de Node.js e de assinar nosso Feed de notícias para se aprofundar cada vez mais
no assunto e ser você também um entusiásta desta tecnologia.
O que é Node.js?
Node.js é uma plataforma construída sobre o motor JavaScript do Google Chrome para
facilmente construir aplicações de rede rápidas e escaláveis. Node.js usa um modelo de I/O
direcionada a evento não bloqueante que o torna leve e eficiente, ideal para aplicações em
tempo real com troca intensa de dados através de dispositivos distribuídos.
Na JSConf 2009 Européia, um programador jovem chamado Ryan Dahl, apresentou um
projeto em que estava trabalhando. Este projeto era uma plataforma que combinava a
máquina virtual JavaScript V8 da Google e um laço de eventos. O projeto apontava para uma
direção diferente das outras plataformas em JavaScript que rodam no servidor: todos I/O
primitivos são orientado a evento. Aproveitando o poder e a simplicidade do Javascript, isso
tornou tarefas difíceis de escrever aplicações assíncronas em tarefas fáceis. Desde quando foi
aplaudido de pé no final do seu discurso, o projeto de Dahl tem recebido uma popularidade e
uma aprovação sem precedentes.
Que problema o Node pode resolver?
Node estabeleceu o objetivo número um que é “fornecer uma maneira fácil para construir
programas de rede escaláveis”. Qual é o problema com os programas servidores atuais?
Vamos fazer os cálculos. Em linguagens como Java™ e PHP, cada conexão cria uma nova thread
que potencialmente tem anexado 2 MB de memória com ela. Em um sistema que tenha 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 o número de usuários aumenta, se você quer que sua aplicação web
suporte mais usuários, você tem que adicionar mais e mais servidores. Somado a estes custos
também podem haver possíveis problemas técnicos: um usuário pode usar diferentes
servidores para cada requisição, então cada recurso compartilhado deve ser compartilhado
para todos os servidores. Por todas estas rações, o gargalho 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.
Node resolve esta questão trocando a maneira 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. 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. Node também alega que um servidor rodando ele pode
suportar dezenas de milhares de conexões simultâneas.
Então, agora que você tem um programa que pode manipular dezenas de milhares de
conexões simultâneas, o que você pode realmente fazer com o Node? Seria incrível se você
tivesse uma aplicação web que necessitasse desta quantidade de conexões. Este é um
daqueles tipos de problema: “se você tem um problema, não é mais um problema”.
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 92
O que Node definitivamente não é?
Sim, Node é um servidor de programas. Entretanto o produto base do Node definitivamente
não é como o Apache ou o Tomcat. Estes servidores são basicamente servidores ready-to-
install e estão prontos para instalar aplicativos instantâneamente. Você pode subir e rodar um
servidor em um minuto com estes produtos. Node definitivamente não é isso. Parecido com
como o Apache pode adicionar um módulo PHP para permitir desenvolvedores criarem
páginas da web dinâmicas, e um módulo SSL para conexões seguras, Node tem o conceito de
módulos que podem ser adicionados no núcleo do Node. Há literalmente centenas de módulos
para rodarem com o Node, e a comunidade é bastante ativa em produzir, publicar e atualizar
dezenas de módulos por dia.
Como o Node funciona
O Node roda em uma JavaScript V8 VM. Mas espere, JavaScript no servidor? Isso, você leu
certo. JavaScript no lado do servidor pode ser um conceito novo para todos que trabalharam
exclusivamente com o JavaScript no lado do cliente, mas a idéia em sí não é tão absurda -
porque não usar a mesma linguagem de programação no cliente que você usa no servidor?
O que é V8? O motor JavaScript V8 é o motor que a Google usa com seu navegador Chrome.
Poucas pessoas pensam sobre o que realmente acontece com o JavaScript no lado do cliente.
Bem, a engine JavaScript realmente interpreta o código e o executa. Com o V8 a Google criou
um ultra-rápido interpretador escrito em C++, com um outro aspecto único: você pode baixar
a engine e incorporá-la em qualquer aplicação desejada. Isso não está restrito em rodar em um
navegador. Então Node atualmente usa o motor JavaScript V8 escrito pela Google e propõe
que seja usado no servidor. Perfeito! Para que criar uma nova linguagem quando há uma boa
solução já disponível?
Programação orientada a Evento
Muitos programadores foram ensinados a acreditar que a programação orientada a objetos
é um modelo de programação perfeito e a não usarem nada mais. Node utiliza o que é
chamado modelo de programação orientada a evento.
Programação orientada a evento no lado do cliente com jQuery:
// jQuery code on the client-side showing how Event-Driven programming works
// When a button is pressed, an Event occurs - deal with it
// directly right here in an anonymous function, where all the
// necessary variables are present and can be referenced directly
$("#myButton").click(function(){
if ($("#myTextField").val() != $(this).val())
alert("Field must match button text");
});
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 93
O lado do servidor na verdade não é diferente do ladodo cliente. Claro que não há botões
sendo pressionados e não há campos de texto sendo escritos, mas em um nível mais alto, os
eventos estão ocorrendo. Uma conexão é feita - evento! Dado é recebido através da conexão -
evento! Data parou de chegar através da conexão - evento!
Por que é que este tipo de configuração é ideal para o Node? JavaScript é uma excelente
linguagem para programação orientada a evento, porque ela permite funções anônimas e
encerramentos, e o mais importante, a sintaxe é familiar para quase todos que já
programaram na vida. As funções de callback que são chamadas quando um evento ocorre
podem ser escritas no mesmo lugar onde você captura o evento. Fácil para desenvolver, fácil
para manter. Sem frameworks complicados de Orientação a Objeto, sem interfaces, nenhum
potencial para o excesso de arquitetura de qualquer coisa. Basta escutar um evento, escrever
uma função de callback, e o Node toma conta de tudo.
8° Capítulo
Um pouco dos conceitos da linguagem
JavaScript
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 94
O que é Node.js?
Node.js é uma plataforma construída sobre o motor JavaScript do Google Chrome para
facilmente construir aplicações de rede rápidas e escaláveis. Node.js usa um modelo de I/O
direcionada a evento não bloqueante que o torna leve e eficiente, ideal para aplicações em
tempo real com troca intensa de dados através de dispositivos distribuídos.
Na JSConf 2009 Européia, um programador jovem chamado Ryan Dahl, apresentou um
projeto em que estava trabalhando. Este projeto era uma plataforma que combinava a
máquina virtual JavaScript V8 da Google e um laço de eventos. O projeto apontava para uma
direção diferente das outras plataformas em JavaScript que rodam no servidor: todos I/O
primitivos são orientado a evento. Aproveitando o poder e a simplicidade do Javascript, isso
tornou tarefas difíceis de escrever aplicações assíncronas em tarefas fáceis. Desde quando foi
aplaudido de pé no final do seu discurso, o projeto de Dahl tem recebido uma popularidade e
uma aprovação sem precedentes.
Que problema o Node pode resolver?
Node estabeleceu o objetivo número um que é “fornecer uma maneira fácil para construir
programas de rede escaláveis”. Qual é o problema com os programas servidores atuais?
Vamos fazer os cálculos. Em linguagens como Java™ e PHP, cada conexão cria uma nova thread
que potencialmente tem anexado 2 MB de memória com ela. Em um sistema que tenha 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 o número de usuários aumenta, se você quer que sua aplicação web
suporte mais usuários, você tem que adicionar mais e mais servidores. Somado a estes custos
também podem haver possíveis problemas técnicos: um usuário pode usar diferentes
servidores para cada requisição, então cada recurso compartilhado deve ser compartilhado
para todos os servidores. Por todas estas rações, o gargalho 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.
Node resolve esta questão trocando a maneira 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. 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. Node também alega que um servidor rodando ele pode
suportar dezenas de milhares de conexões simultâneas.
Então, agora que você tem um programa que pode manipular dezenas de milhares de
conexões simultâneas, o que você pode realmente fazer com o Node? Seria incrível se você
tivesse uma aplicação web que necessitasse desta quantidade de conexões. Este é um
daqueles tipos de problema: “se você tem um problema, não é mais um problema”.
O que Node definitivamente não é?
Sim, Node é um servidor de programas. Entretanto o produto base do Node definitivamente
não é como o Apache ou o Tomcat. Estes servidores são basicamente servidores ready-to-
install e estão prontos para instalar aplicativos instantâneamente. Você pode subir e rodar um
servidor em um minuto com estes produtos. Node definitivamente não é isso. Parecido com
como o Apache pode adicionar um módulo PHP para permitir desenvolvedores criarem
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 95
páginas da web dinâmicas, e um módulo SSL para conexões seguras, Node tem o conceito de
módulos que podem ser adicionados no núcleo do Node. Há literalmente centenas de módulos
para rodarem com o Node, e a comunidade é bastante ativa em produzir, publicar e atualizar
dezenas de módulos por dia.
Como o Node funciona
O Node roda em uma JavaScript V8 VM. Mas espere, JavaScript no servidor? Isso, você leu
certo. JavaScript no lado do servidor pode ser um conceito novo para todos que trabalharam
exclusivamente com o JavaScript no lado do cliente, mas a idéia em sí não é tão absurda -
porque não usar a mesma linguagem de programação no cliente que você usa no servidor?
O que é V8? O motor JavaScript V8 é o motor que a Google usa com seu navegador Chrome.
Poucas pessoas pensam sobre o que realmente acontece com o JavaScript no lado do cliente.
Bem, a engine JavaScript realmente interpreta o código e o executa. Com o V8 a Google criou
um ultra-rápido interpretador escrito em C++, com um outro aspecto único: você pode baixar
a engine e incorporá-la em qualquer aplicação desejada. Isso não está restrito em rodar em um
navegador. Então Node atualmente usa o motor JavaScript V8 escrito pela Google e propõe
que seja usado no servidor. Perfeito! Para que criar uma nova linguagem quando há uma boa
solução já disponível?
Programação orientada a Evento
Muitos programadores foram ensinados a acreditar que a programação orientada a objetos
é um modelo de programação perfeito e a não usarem nada mais. Node utiliza o que é
chamado modelo de programação orientada a evento.
Programação orientada a evento no lado do cliente com jQuery:
// jQuery code on the client-side showing how Event-Driven programming works
// When a button is pressed, an Event occurs - deal with it
// directly right here in an anonymous function, where all the
// necessary variables are present and can be referenced directly
$("#myButton").click(function(){
if ($("#myTextField").val() != $(this).val())
alert("Field must match button text");
});
O lado do servidor na verdade não é diferente do lado do cliente. Claro que não há botões
sendo pressionados e não há campos de texto sendo escritos, mas em um nível mais alto, os
eventos estão ocorrendo. Uma conexão é feita - evento! Dado é recebido através da conexão -
evento! Data parou de chegar através da conexão - evento!
Por que é que este tipo de configuração é ideal para o Node? JavaScript é uma excelente
linguagem para programação orientada a evento, porque ela permite funções anônimas e
encerramentos, e o mais importante, a sintaxe é familiar para quase todos que já
programaram na vida. As funções de callback que são chamadas quando um evento ocorre
podem ser escritas no mesmo lugar onde você captura o evento. Fácil para desenvolver, fácil
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 96
para manter. Sem frameworkscomplicados de Orientação a Objeto, sem interfaces, nenhum
potencial para o excesso de arquitetura de qualquer coisa. Basta escutar um evento, escrever
uma função de callback, e o Node toma conta de tudo.
Nodejs e MongoDB - Introdução ao Mongoose
Mongoose é uma biblioteca do Nodejs que proporciona uma solução baseada em esquemas
para modelar os dados da sua aplicação. Ele possui sistema de conversão de tipos, validação,
criação de consultas e hooks para lógica de negócios.
Mongoose fornece um mapeamento de objetos do MongoDB similar ao ORM (Object
Relational Mapping), ou ODM (Object Data Mapping) no caso do Mongoose. Isso significa que
o Mongoose traduz os dados do banco de dados para objetos JavaScript para que possam ser
utilizados por sua aplicação.
Obs: Este artigo vai assumir que você tem o Nodejs e o MongoDB instalados. Você precisa
estar com o MongoDB rodando em seu computador para poder fazer os seguintes exemplos.
Instalando o pacote Mongoose
Utilizando o [NPM][] via linha de comando é muito simples fazer a instalação dos pacotes do
Nodejs. Para fazer a instalação do Mongoose, execute a seguinte linha de comando que o NPM
cuidará de instalar a versão estável mais recente do pacote requerido:
npm install Mongoose
Conectando com o MongoDB
Neste artigo vamos conectar o Mongoose com o banco de dados de testes que o MongoDB
define quando você o inicializa pelo console e vamos garantir que qualquer erro de conexão
seja impresso no console.
var Mongoose = require('Mongoose');
var db = Mongoose.connection;
db.on('error', console.error);
db.once('open', function() {
console.log('Conectado ao MongoDB.')
// Vamos adicionar nossos Esquemas, Modelos e consultas aqui
});
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 97
Mongoose.connect('mongodb://localhost/test');
Ao executar nossa aplicação de exemplo podemos observar no console do MongoDB que
foram abertas 5 conexões simultâneas. Isto ocorre porque o Mongoose usa um conjunto de 5
conexões simultâneas por padrão que são compartilhadas por toda sua aplicação. Para
melhorar o desempenho das nossas aplicações vamos deixá-las abertas, porém você pode
alterar o comportamento padrão adicionando parâmetros opcionais ao Mongoose.connect() -
o parâmetro poolSize define a quantidade de conexões simultâneas. Veja abaixo a saída do
meu MongoDB exibindo que foram abertas 5 conexões simultâneas:
Sat Aug 31 11:12:21.827 [initandlisten] connection accepted from 127.0.0.1:64413 #2 (1
connection now open)
Sat Aug 31 11:12:21.830 [initandlisten] connection accepted from 127.0.0.1:64414 #3 (2
connections now open)
Sat Aug 31 11:12:21.831 [initandlisten] connection accepted from 127.0.0.1:64415 #4 (3
connections now open)
Sat Aug 31 11:12:21.831 [initandlisten] connection accepted from 127.0.0.1:64416 #5 (4
connections now open)
Sat Aug 31 11:12:21.832 [initandlisten] connection accepted from 127.0.0.1:64417 #6 (5
connections now open)
Esquemas e Modelos
Para começar vamos precisar de um esquema e um modelo para que possamos trabalhar
com os dados que serão persistidos em nosso banco de dados MongoDB. Esquemas definem a
estrutura dos documentos dentro de uma coleção e modelos são usados para criar instâncias
de dados que serão armazenados em documentos. Nós vamos fazer um banco de dados de
filmes para acompanhar os filmes que tem cenas extras após os créditos finais (também
chamado de ‘credit cookies’). O código abaixo mostra nosso esquema movieSchema e nosso
modelo Movie criado.
var movieSchema = new Mongoose.Schema({
title: { type: String },
rating: String,
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 98
releaseYear: Number,
hasCreditCookie: Boolean
});
var Movie = Mongoose.model('Movie', movieSchema);
A última linha deste código compila o modelo Movie utilizando o esquema movieSchema
como estrutura. O Mongoose também cria uma coleção no MongoDB chamada Movies para
estes documentos.
Você pode notar que o modelo Movie está em letra maiúscula, isto porque quando um
modelo é compilado é retornado uma função construtora que será usada para criar as
instâncias do modelo. As instâncias criadas pelo construtor do modelo são documentos que
serão persistidos pelo MongoDB ao utilizar a função save.
Criar, Recuperar, Atualizar e Deletar (CRUD)
Criar um novo documento Movie é fácil agora que já definimos o modelo, basta
instancializar o modelo Movie e salvar esta instância na base. Atualizar é igualmente fácil, faça
suas modificações e então chame a função save do seu documento.
var thor = new Movie({
title: 'Thor',
rating: 'PG-13',
releaseYear: '2011', // Note o uso de String ao inves de Number
hasCreditCookie: true
});
thor.save(function(err, thor) {
if (err) return console.error(err);
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 99
console.dir(thor);
});
Observe que utilizamos uma String ao invés de um Número no campo releaseYear e o
Mongoose vai se encarregar de converter o dado para tipo especificado no esquema.
Quando adicionamos estes dois códigos dados à nossa aplicação e executamos vemos que a
função save vai fornecer um documento recém criado, observado pelo que foi impresso no
console de nossa aplicação.
{ __v: 0,
title: 'Thor',
rating: 'PG-13',
releaseYear: 2011,
hasCreditCookie: true,
_id: 5222012cb65eddf003000001 }
Coleções no MongoDB possuem esquemas flexíveis, isto quer dizer que coleções não
impõem a estrutura dos documentos. Na prática isto significa que documentos da mesma
coleção não precisam ter o mesmo conjunto de campos ou estrutura, e campos comuns em
documentos de uma coleção podem carregar diferentes tipos de dados. Como foi visto em
nosso exemplo, utilizando o Mongoose para mapear nossa base, ele padroniza os documentos
de um mesmo esquema a fim garantir que instâncias do modelo que compilou aquele
esquema sempre tenham o mesmo tipo de dados nos atributos especificados pelo esquema.
MongoDB também possui uma estrutura de dados chamada índice que permite você
localizar rápidamente documentos baseado nos valores armazenados em certos campos
específicos. Fundamentalmente, índices no MongoDB é similar à índices em outros sistemas de
banco de dados. Em nosso exemplo o índice do modelo criado é _id.
Recuperando um documento da base
Diferentes maneiras podem ser utilizadas para recuperar um documento existente na base
de dados. Você pode buscar documentos baseado em qualquer propriedade do esquema e
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 100
você pode buscar qualquer quantidade de documentos. Utilize findOne para limitar os
resultados a um único documento.
// Buscando um unico filme pelo nome
Movie.findOne({ title: 'Thor' }, function(err, thor) {
if (err) return console.error(err);
console.dir(thor);
});
// Buscando todos os filmes
Movie.find(function(err, movies) {
if (err) return console.error(err);
console.dir(movies);
});
// Buscando todos os filmes que possuem 'credit cookie'.
Movie.find({ hasCreditCookie: true }, function(err, movies) {if (err) return console.error(err);
console.dir(movies);
});
Mongoose também permite você criar funções auxiliares estáticas para buscar seus dados.
Para isso você deve atribuir sua função estática ao esquema antes de ser feita compilação para
o modelo.
movieSchema.statics.findAllWithCreditCookies = function(callback) {
return this.find({ hasCreditCookie: true }, callback);
};
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 101
var Movie = Mongoose.model('Movie', movieSchema);
// Utilizadno a funcao auxiliar estatica do modelo 'Movie' compilado
Movie.findAllWithCreditCookies(function(err, movies) {
if (err) return console.error(err);
console.dir(movies);
});
Isso é tudo que precisa fazer para manipular os dados em MongoDB. Mongoose faz esta
tarefa muito simples então você pode desenvolver seus serviços rapidamente. Usando isso
junto com suas habilidades com Express, você pode desenvolver um aplicativo web muito bom
e funcional.
Abaixo está um código utilizando os conceitos aqui apresentados que implementa a função
auxiliar estática, para buscar todos filmes com ‘credit cookies’, salva 3 filmes do Thor com
‘credit cookies’ e em seguida cria um Timeout para buscar os filmes utilizando a função auxiliar
1 segundo depois - Isto é feito pois como estamos trabalhando com IO não bloqueante o Node
não aguarda o tempo de salvar os filmes antes de prosseguir, por isso damos um tempo para
se certificar que eles foram salvos antes de buscá-los.
var Mongoose = require('Mongoose');
var db = Mongoose.connection;
db.on('error', console.error);
db.once('open', function() {
// Create your schemas and models here.
console.log('Conectado.')
var movieSchema = new Mongoose.Schema({
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 102
title: { type: String },
rating: String,
releaseYear: Number,
hasCreditCookie: Boolean
});
movieSchema.statics.findAllWithCreditCookies = function(callback) {
return this.find({ hasCreditCookie: true }, callback);
};
var Movie = Mongoose.model('Movie', movieSchema);
for (var i =1; i<=3; i++){
var thor = new Movie({
title: 'Thor ' + i,
rating: 'PG-13',
releaseYear: '2011', // Note o uso de String ao inves de Number
hasCreditCookie: true
});
thor.save(function(err, thor) {
if (err) return console.error(err);
console.log('Salvo: ')
console.dir(thor);
});
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 103
}
setTimeout(function(){
// Utilizadno a funcao auxiliar estatica do modelo 'Movie' compilado
Movie.findAllWithCreditCookies(function(err, movies) {
if (err) return console.error(err);
console.log('Buscado: ')
console.dir(movies);
});
}, 1000);
});
Mongoose.connect('mongodb://localhost/test');
Mineração de dados e as funções map, reduce e filter
Este artigo vai mostrar como é simples fazer uma mineração de dados na Internet com o
Nodejs e demonstrando como utilizar funções muito úteis do JavaScript: map, reduce e filter.
Bancos de dados não-relacionais (NoSQL), como o CouchDB e o mongoDB, utilizam o
MapReduce, que é uma combinação das funções map e reduce apresentadas aqui, para
efetuarem suas consultas na base de dados. Eles implementam funções de maneira muito
similares às do JavaScript e este é o melhor motivo para compreender o funcionamento desta
operação.
O texto também serve de base para quem deseja fazer um web crawler, também chamado
de web spider, que são programas que acessam páginas da web e extraem informações
relevantes de seu conteúdo. Os motores de busca, como a Google e o Bing, utilizam esta
técnica para manterem suas bases de dados atualizadas. Os crawlers também são utilizados
para varrer a Internet a fim de minerar endereços de email e dados pessoais.
Buscando o conteúdo na Web
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 104
A fonte de dados utilizada será o Feed RSS do HackerNews, como o RSS está em XML
podemos tratá-lo da mesma forma que um documento HTML.
Para dar início ao nosso projeto temos que criar nosso aplicativo e fazer com que ele
busque todo o Feed para que seja possível fazer a extração dos dados. Para isso será utilizado
a função get do módulo https. Observe como o aplicativo exemplo app.js ficou.
// app.js
var https = require('https');
function getCallback(response){
var body = '';
console.log("Temos uma resposta: " + response.statusCode);
response.on('data', function (chunk) {
body += chunk;
});
response.on('end', function(){
console.log("Corpo da mensagem: " + body.slice(0,200) + '...');
});
}
https.get('https://news.ycombinator.com/bigrss', getCallback)
.on('error', function(e){
console.log("Ocorreu um erro: " + e.message);
});
Vamos acompanhar o que é feito neste código passo a passo. Primeiro importamos o
módulo https que buscará o endereço da web que queremos. Depois definimos a função
getCallback que, como o nome sugere, será a função callback do nosso https.get(), ela recebe
o objeto response como argumento e é adicionado um event listner para o evento data, que
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 105
concatena a resposta na variável body, e um event listner para o evento end, que chama a
função console.log() quando a resposta de nossa requisição está completa. Por último
executamos o método https.get() passando como parâmetro o endereço do Feed que vamos
buscar e a função callback que tratará a resposta, adicionamos também um event listner para
o evento error que nos indicará se ocorreu algum erro durante nossa requisição.
É interessante ressaltar que o Node trabalha com eventos, então cada pacote recebido
como resposta é um evento que deve ser tratado no nosso objeto response, por isso temos
que concatenar toda a resposta a fim de trabalhar com o corpo completo da página
requisitada.
Minerando os dados
Agora que temos o corpo da página temos que fazer a extração dos dados que queremos e
do jeito que queremos. Neste exemplo vamos demonstrar as habilidades das funções map,
reduce e filter desenvolvendo um contador de palavras dos títulos dos posts. Ele contará o
número de ocorrências de cada palavrá e retornará uma lista de túplas [palavra,
nro_ocorrências] das palavras que ocorreram mais de 10 vezes nos títulos.
Como foi dito, a base de dados que vamos minerar está em RSS então ela pode ser tratada
da mesma forma que uma página HTML. Para isso podemos utilizar o jQuery para extrair a
informação formatada.
Para utilizar as funções do núcleo do jQuery no servidor podemos tanto utilizar a própria
biblioteca jQuery, desenvolvida para o navegador, como utilizar a biblioteca Cheerio, que é
uma implementação rápida, flexível e limpa do core do jQuery designada específicamente para
o servidor. Matthew Mueller diz que seus benchmarks sugerem que Cheerio seria 8 vezes maisrápida que a implementação do jQuery para o navegador.
Antes de utilizá-la, vamos fazer a instalação do pacote do Cheerio para em nosso aplicativo.
Para isso basta instalá-lo utilizando a NPM via linha de comando:
npm install cheerio
Vamos, então, importar o módulo para nosso aplicativo e criar uma função para minerar os
dados da página requisitada. Vamos chamar nossa função de minerarDados() e passar para ela
o corpo da resposta recebida pela função getCallback(). O código do nosso exemplo ficaria
assim:
var https = require('https'),
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 106
cheerio = require('cheerio');
function minerarDados(body){
var $ = cheerio.load(body);
var titles = $('title');
console.log(titles.slice(0,2));
}
function getCallback(response){
var body = '';
console.log("Got response: " + response.statusCode);
response.on('data', function (chunk) {
body += chunk;
});
response.on('end', function(){
minerarDados(body);
});
}
https.get('https://news.ycombinator.com/bigrss', getCallback)
.on('error', function(e){
console.log("Ocorreu um erro: " + e.message);
});
Agora nossa função minerarDados() conseguiu extrair os objetos do tipo tag de nome title e
imprime dois deles no console. Ok, ela extrai todos os títulos do Feed RSS, porém temos um
problema, $('title') retorna uma lista de nós (NodeList). Vamos então aplicar o MapReduce
para extrair a informação que desejamos e por último filtrar os resultados indesejados.
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 107
Para converter-mos nossa lista de nós em um Array contendo apenas o conteúdo de texto
dos nomes vamos primeiro transformar nossa NodeList em um Array de objetos utilizando a
função Array.prototype.slice.call() e neste array de objetos vamos aplicar a função map() do
JavaScript, o código ficaria assim.
var titles = Array.prototype.slice.call($('title')).map(
function(node, index, context) {
return $(node).text();
});
array.map(callback[, thisArg])
A função map() recebe dois parâmetros mas normalmente apenas o primeiro é
especificado. O primeiro parâmetro é uma função de callback que será chamada sobre todos
os elementos no Array. O segundo parâmetro é utilizado para especificar o valor para o objeto
this durante a execução da função. O mais importante são os parâmetros passados para a
função de callback, eles são: o elemento do Array em sí, o índice do Array, e todo o Array
(contexto). A assinatura da função de callback se parece com essa:
var callback = function(elemento, indice, contexto) { /* omitido */ }
Porém também podemos utilizar a função map() do jQuery implementada pelo Cheerio,
mas para isso é preciso ter atenção pois a assinatura da função callback do jQuery é
ligeiramente diferente, em seus parâmetros primeiro vem o índice do elemento seguido do
elemento em sí. Sua assinatura é assim:
var callback = function(indice, elemento) { /* omitido */ }
Para implementar utilizando a função map() do jQuery é preciso fazer ligeiras modificações,
o código deverá se parecer com isto:
var titles = $('title').map(
function(index, node) {
return $(node).text();
});
Eliminando pontuações desnecessárias
Agora que já temos um Array de strings contento o texto de todos os títulos da nossa base
de dados que estamos explorando. Você já deve ter notado que os títulos não contém apenas
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 108
letras, eles também contém números e pontuações. Estes são desnecessários em nosso
contador de palavras, então vamos tratar de removê-los. Isto pode ser feito nesta mesma
chamada map() utilizando expressão regular.
var words = $('title')
.map(function(index, node) {
return $(node).text().toLowerCase().match(/([a-z]+)/g);
});
Se você já utilizou RegEx (expressões regulares) no JavaScript você sabe que isso gera um
efeito colateral: Esta função retorna Arrays com todas as palavras que passaram na RegEx
individualmente. Contudo esse é um efeito colateral útil para nós pois só precisamos das
palavras, no entanto temos mais um problema: o Array words retornado é de duas dimensões,
isso que significa que temos que achatá-lo para apenas uma dimensão. Este é um bom
momento para fazer uso da função reduce() do JavaScript.
var words = $('title')
.map(function(index, node) {
return $(node).text().toLowerCase().match(/([a-z]+)/g);
})
.reduce(function(last, now){
return last.concat(now)
}, []);
array.reduce(callback[, initialValue])
Assim como map, reduce recebe dois argumentos. O primeiro é novamente a função de
callback, que será chamada para cada elemento no Array. O segundo parâmetro é o
initialValue que será de fácil entendimento quando você ver a assinatura da função de
callback:
var callback = function(valorAnterior, valorAtual, indice, contexto) { /* omitted */ }
Como você pôde ver, o primeiro parâmetro passado para a função de callback é o valor
anterior. Se você precisar somar um Array de números, isso não será problema. Mas em nosso
caso nós precisamos retornar um Array, então nós especificamos um valor inicial para o
valorAnterior, neste caso um Array vazio [] onde serão adicionados os elementos de nossa
antiga Array bi-dimensional.
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 109
Contando as palavras
Para esta tarefa podemos utilziar reduce novamente, mas antes de fazê-lo, vou mostrar
como o resultado vai se parecer:
[['the', 'on', 'news', 'hacker', ...], [50, 66, 20, 19, ...]]
Isso será uma Array de duas dimensões novamente. São dois Arrays dentro de um Array, e
o índice da palavra no primeiro Array corresponderá com o índice do número de vezes que ela
ocorre nos títulos no segundo Array. Para fazer isso vamos utilizar reduce e vamos especificar
uma Array 2d vazia como valor inicial: [[], []].
var scores = $('title')
.map(function(index, node) {
return $(node).text().toLowerCase().match(/([a-z]+)/g);
})
.reduce(function(last, now){
return last.concat(now)
}, [])
.reduce(function(last, now){
var index = last[0].indexOf(now);
if (index === -1) {
last[0].push(now);
last[1].push(1);
} else {
last[1][index] += 1;
}
return last;
}, [[], []]);
Comprimindo os Arrays
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 110
Estamos próximos de concluirmos nossa coleção de dados. Tudo que devemos fazer agora é
combinar as duas Arrays em uma. O formato final do Array será este:
[['the', 50], ['on', 66], ['news', 20], ['hacker', 19], ...]
O JavaScript não implementa a função zip() nativamente, nós poderíamos utilziar esta
função do pacote Underscore mas como esta função é muito simples de ser implementada
vamos implementar nós mesmos a mesclagem dos valores destas listas.
var zip = [];
scores[0].forEach(function(word, i) {
zip.push([word, scores[1][i]])
});
Filtrando os dados
Lembrando que nossa aplicação só se interessapor palavras que ocorreram mais de 10
vezes, a fim de filtrar as palavras menos importantes da lista, então vamos implementar esta
última funiconalidade. Para isto podemos utilizar a função nativa do JavaScript filter da
seguinte maneira:
var filtered = zip.filter(function (element){
return element[1] >= 10
});
array.filter(callback[, thisObject])
Os parâmetros da função filter são exatamente os mesmos da função map já apresentada,
ela possui dois parâmetros porém normalmente só o primeiro é especificado. O primeiro
parâmetro é uma função de callback que será chamada sobre todos os elementos no Array. O
segundo parâmetro é utilizado para especificar o valor para o objeto this durante a execução
da função. O importante é a função de callback, seus parâmetros são: o elemento do Array em
sí, o índice do Array e todo o Array (contexto). A assinatura da função de callback se parece
com essa:
var callback = function(elemento, indice, contexto) { /* omitido */ }
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 111
Esta função retorna verdadeiro ou falso para filtrar os elementos que continuam no Array e
os elementos que são excluídos do Array. Quando fizemos element[1] >= 10 utilizamos o
operador lógico de comparação que retorna verdadeiro para todos os elementos cujo valor do
índice 1 seja maior ou igual a 10 e falso caso contrário - o índice 1 guarada a quantidade de
vezes que a palavra ocorreu nos títulos.
Conclusão
Agora nosso exemplo está concluido e conseguímos fazer a mineração dos dados que
queríamos dos Feeds do HackerNews. O código final ficou assim:
var https = require('https'),
cheerio = require('cheerio');
function minerarDados(body){
var $ = cheerio.load(body);
var scores = $('title')
.map(function(index, node) {
return $(node).text().toLowerCase().match(/([a-z]+)/g);
})
.reduce(function(last, now){
return last.concat(now)
}, [])
.reduce(function(last, now){
var index = last[0].indexOf(now);
if (index === -1) {
last[0].push(now);
last[1].push(1);
} else {
last[1][index] += 1;
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 112
}
return last;
}, [[], []]);
var zip = [];
scores[0].forEach(function(word, i) {
zip.push([word, scores[1][i]])
});
var filtered = zip.filter(function (element){
return element[1] >= 10
});
console.log(filtered.slice(0,20));
}
function getCallback(response){
var body = '';
console.log("Got response: " + response.statusCode);
response.on('data', function (chunk) {
body += chunk;
});
response.on('end', function(){
minerarDados(body);
});
}
https.get('https://news.ycombinator.com/bigrss', getCallback)
.on('error', function(e){
console.log("Ocorreu um erro: " + e.message);
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 113
});
O exemplo apresentado funcionou corretamente e conseguiu extrair a informação da base
da Internet escolhida e imprimir os 20 primeiros elementos do nosso Array no console
console.log(filtered.slice(0,20));.
O artigo teve como finalidade ensinar os leitores como é fácil fazer tal operação utilizando o
Nodejs e as funções nativas do JavaScript, podendo ser utilizado como base para
desenvolvimento de aplicações mais complexas como robôs de web crawling entre outros.
Como evitar o inferno de callbacks
Este artigo é um guia para se escrever programas assíncronos em JavaScript que expõe dicas
para se evitar o ‘inferno de callbacks’.
O bom entendimento de callbacks é essencial para a programação orientada a eventos do
Node, este é o nome dado a funções que serão executadas de modo assíncrono, ou
posteriormente. Caso tenha dúvidas do que é uma função callback você pode ler o artigo
explicando callbacks em Node.
O que é o ‘inferno de callbacks’
JavaScript assíncrono, ou JavaScript que usa callbacks é difícil de se entender
intuitivamente. Muitos códigos acabam se parecendo como este:
fs.readdir(source, function(err, files) {
if (err) {
console.log('Error finding files: ' + err)
} else {
files.forEach(function(filename, fileIndex) {
console.log(filename)
gm(source + filename).size(function(err, values) {
if (err) {
console.log('Error identifying file size: ' + err)
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 114
} else {
console.log(filename + ' : ' + values)
aspect = (values.width / values.height)
widths.forEach(function(width, widthIndex) {
height = Math.round(width / aspect)
console.log('resizing ' + filename + 'to ' + height + 'x' + height)
this.resize(width, height).write(destination + 'w' + width + '_' + filename, function(err) {
if (err) console.log('Error writing file: ' + err)
})
}.bind(this))
}
})
})
}
})
Você consegue ver quantas functions e }) têm neste código? Isto é carinhosamente
conhecido como o inferno de callbacks.
Escrever códigos melhores não é difícil, você só precisa saber algumas coisas.
Nomeie suas funções
Aqui esta um confuso código em JavaScript que roda no navegador que utiliza browser-
request para fazer uma requisição AJAX para o servidor.
var form = document.querySelector('form')
form.onsubmit = function(submitEvent) {
var name = document.querySelector('input').value
request({
uri: "http://example.com/upload",
body: name,
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 115
method: "POST"
}, function(err, response, body) {
var statusMessage = document.querySelector('.status')
if (err) return statusMessage.value = err
statusMessage.value = body
})
}
O código possui duas funções anônimas, observe como fica o código quando damos nomes
a estas funções.
var form = document.querySelector('form')
form.onsubmit = function formSubmit(submitEvent) {
var name = document.querySelector('input').value
request({
uri: "http://example.com/upload",
body: name,
method: "POST"
}, function postResponse(err, response, body) {
var statusMessage = document.querySelector('.status')
if (err) return statusMessage.value = err
statusMessage.value = body
})
}
Como você pode ver nomear as funções é muito fácil e traz algumas coisas boas para seu
código:
Facilita a leitura do código
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 116
Quando acontecem exceções você pega rastreamento da pilha (stacktraces) que referencia
o nome atual da função ao invés de “anonymous”
Permite você manter seu código mais raso, ou não aninhado profundamente
Mantenha seu código raso
Aproveitando o exemplo apresentado, vamos um pouco mais longe e se livrar do nível triplo
deaninhamento que há no código.
function formSubmit(submitEvent) {
var name = document.querySelector('input').value
request({
uri: "http://example.com/upload",
body: name,
method: "POST"
}, postResponse)
}
function postResponse(err, response, body) {
var statusMessage = document.querySelector('.status')
if (err) return statusMessage.value = err
statusMessage.value = body
}
document.querySelector('form').onsubmit = formSubmit
Códigos como este facilitam a leitura e a manutenção posterior.
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 117
Modularize seu código
Esta é a parte mais importante: Qualquer pessoa é capaz de criar módulos (biblioteca AKA).
Citando Isaac Schlueter (do projeto do Node): “Escreva módulos pequenos onde cada um faça
uma coisa, e monte-os em outros módulos que fazem coisas maiores. Você não entra no
inferno de callback se você não ir para lá.”
Vamos pegar o exemplo apresentado e transformá-lo em um módulo dividindo-o em um
par de arquivos. Aqui será apresentado um método simples que funciona tanto no navegador
como no servidor.
Vamos criar um arquivo chamado formuploader.js que contém nossas duas funções
apresentadas anteriormente.
function formSubmit(submitEvent) {
var name = document.querySelector('input').value
request({
uri: "http://example.com/upload",
body: name,
method: "POST"
}, postResponse)
}
function postResponse(err, response, body) {
var statusMessage = document.querySelector('.status')
if (err) return statusMessage.value = err
statusMessage.value = body
}
exports.submit = formSubmit
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 118
A variável exports da última linha é um exemplo do sistema de módulos CommonJS. O bom
deste sistema de módulos é que ele é muito simples - você só precisa definir o que deve ser
compartilhado quando o módulo for importado, para isto é utilizado a variável local exports do
módulo. Para compreender melhor como funciona a importação de módulos você pode ler o
artigo que explica como funciona a função require do Node.js;
O Node tem um sistema simples de carregamento de módulos que utiliza o padrão
CommonJS e de fato a maior parte das funções do núcleo do Node é implementada utilizando
módulos escritos em JavaScript. Compreender profundamente o sistema de módulos do Node
é crucial para implementação de códigos legíveis e de fácil manutenção, fundamental para a
maior parte das aplicações. Para entender melhor este assunto acesse o artigo que aborda
detalhadamente os módulos em Node.js.
Para usar módulos no padrão CommonJS no navegador, você pode utilizar a biblioteca
browserify. Esta biblioteca basicamente permite você utilizar a função require para carregar
módulos no seu programa.
Agora que temos o formuploader.js e ele foi carregado na página utilizando a tag HTML
script, nós só precisamos importá-lo e usá-lo. Veja como ficou o código da nossa aplicação
agora:
var formUploader = require('formuploader')
document.querySelector('form').onsubmit = formUploader.submit
Agora nossa aplicação exemplo apresentada só possui duas linhas e tem os seguintes
benefícios:
Facilita o entendimento de novos desenvolvedores - Eles não precisam empacar tentando
ler todas as funções formuploader para entender o que está acontecendo aqui
As funções do formuploader agora podem ser usadas em outros lugares sem a duplicação
de código e pode facilmente ser compartilhaada no GitHub
O código em sí é agradável, simples e fácil de ler
Há muitos padrões de módulos para o navegador e para o servidor. Alguns deles são muito
complicados. Os mostrados aqui são os considerados mais simples de se entender.
E o Promises?
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 119
Promises é o padrão mais abstrato para trabalhar com código assíncrono em JavaScript.
O escopo deste artigo é mostrar como escrever um código agradável em JavaScript. Se você
utiliza uma biblioteca de terceiros que adiciona abstração para seu JavaScript, então certifique-
se de estar disposto a forçar todos que contribuem para a sua biblioteca a também terem os
mesmos pontos de vistas sobre o JavaScript que você.
Max Ogden expõe que utiliza callbacks em 90% do código assíncrono que escreve e quando
as coisas se complicam ele utiliza algo como a biblioteca async, que é um módulo que fornece
funções poderosas para trabalhar com código JavaScript assíncrono, ela foi projetada para
utilizar como o Node.js mas também pode ser utilizada diretamente no navegador.
Leitura adicional
Um padrão para desacoplar eventos DOM (em Inglês)
Módulos em Node.JS
Node tem um sistema simples de carregamento de módulos, a utilização de módulos
permite incluir outros arquivos JavaScript em sua aplicação, este sistema utiliza o formáto de
módulos CommonJS e de fato grande maioria das funcionalidades do núcleo do Node é
implementada utilizando módulos escritos em Javascript, o que significa que você pode ler o
código fonte das bibliotecas do núcleo (core) no Github.
Módulos são cruciais para construção de aplicações em Node pois eles permitem incluir
bibliotecas externas, como bibliotecas de acesso ao banco de dados, e ajudam a organizar seu
código em partes separadas com responsabilidades limitadas. Você deve tentar indentificar
partes reusáveis do seu código e transformá-las em módulos separados para reduzir a
quantidade de código por arquivo e para ficar mais fácil de ler e manter seu código.
Utilizar módulos em Node é simples, você usa a função require(), que recebe um
argumento: o nome da biblioteca do core ou o caminho do arquivo do módulo que você quer
carregar. É aconselhável compreender como funciona a função require do Node.js. Outro
artigo aqui também já tratou como utilizar módulos em sua aplicação Node.js.
A mais expressiva e simples solução para módulos em JavaScript foi adotada como padrão
pelo Node, o padrão CommonJS, que é usado de forma levemente diferente no Node.
CommonJS te dá uma boa sintaxe, e mais importante, módulos de primeira classe. E se você
estiver se perguntando porque módulos de primeira classe são importantes, a resposta é “pela
mesma razão que funções de primeira classe são importantes”.
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 120
Lembrando que na teoria de linguagens de programação, diz-se que algo é um objeto de
primeira classe em uma linguagem quando ele pode ser construído em tempo de execução,
passado como parâmetro, atribuído a uma variável, devolvido como resultado de uma função,
incluído em uma estrutura de dados maior, etc. Na maioria das linguagens de programação os
números e as strings são objetos de primeira classe, mas em muitas linguagens funções não
são objetos de primeira classe. Em Javascript, Python, Ruby, C# e muitas outras linguagens,
sabemos que funções são objetos de primeira classe, e essa facilidade acaba sendo chamado
de “funções de primeira classe”.
Em Node, arquivos e módulos tem correspondência de um para um. Observe o exemplo a
seguir onde nosso módulo calculo.js carrega o módulocirculo.js salvo no mesmo diretório.
// calculo.js
var circulo = require('./circulo.js');
console.log( 'Um circulo de raio 4 tem area de '
+ circulo.area(4));
// circulo.js
var PI = Math.PI;
exports.area = function (r) {
return PI * r * r;
};
exports.circunferencia = function (r) {
return 2 * PI * r;
};
Neste exemplo o módulo circulo.js exportou as funções area() e circunferencia() . Aqui é
apresentado o principal conceito do sistema de carregamento módulos do Node, para um
módulo exportar um objeto, ou um construtor, basta adicioná-lo no objeto especial exports .
Todas as demais variáveis declaradas dentro do módulo serão variáveis privadas do módulo e
não serão exportadas, neste exemplo a variável PI é privada do módulo circulo.js e não é
acessível no escopo de calculo.js .
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 121
É importante frisar que exports é uma referência para module.exports utilizado apenas
para o acréscimo de objetos, caso você queira exportar um único item, como um construtor,
você vai precisar usar o objeto module.exports diretamente. Acompanhe o exemplo do nosso
módulo construtor.js apresentado a seguir.
// construtor.js
function MeuConstrutor (opts) {
//...
}
// CUIDADO A LINHA ABAIXO NAO EXPORTA NADA
exports = MeuConstrutor;
// A linha abaixo exporta o construtor
module.exports = MeuConstrutor;
Note que a linha exports = MeuConstrutor; não irá ter o comportamento esperado, caso o
exemplo parasse nesta linha apenas um objeto vazio seria exportado. Para exportar um único
objeto, ou um construtor como neste exemplo, deve-se utilizar a variável module.exports .
O sistema de módulos é implementado no módulo require("module") .
Importações cíclicas
Quando temos chamadas cíclicas de módulos utilizando a função require() um módulo não
é retornado enquanto não tiver sido executado por completo, e o módulo será salvo em cache
a primeira vez que for carregado.
Acompanhe a situação apresentada a seguir para compreender o dinâmica das importações
cíclicas.
// a.js
console.log('a iniciando');
exports.pronto = false;
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 122
var b = require('./b.js');
console.log('dentro de a, b.pronto = %j', b.pronto);
exports.pronto = true;
console.log('a pronto');
// b.js
console.log('b iniciando');
exports.pronto = false;
var a = require('./a.js');
console.log('dentro de b, a.pronto = %j', a.pronto);
exports.pronto = true;
console.log('b pronto');
// principal.js
console.log('principal iniciando');
var a = require('./a.js');
var b = require('./b.js');
console.log('dentro de principal, a.pronto=%j, b.pronto=%j', a.pronto, b.pronto);
console.log('principal pronto');
Quando o módulo principal.js carrega a.js, por sua vez a.js carrega b.js, neste ponto b.js
tenta carregar a.js . Para evitar um cíclo infinito, de a.js carregando b.js e vice-versa, uma cópia
incompleta do objeto exports de a.js é retornada para o módulo b.js . Então b.js completa seu
carregamento, e seu objeto exports é fornecido para o módulo a.js .
Quando principal.js terminar de carregar, ambos os módulos estarão prontos. A saída deste
programa seria assim:
$ node principal.js
principal iniciando
a iniciando
b iniciando
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 123
dentro de b, a.pronto = false
b pronto
dentro de a, b.pronto = true
a pronto
dentro de principal, a.pronto=true, b.pronto=true
principal pronto
Esta foi a forma que os desenvolvedores do Node utilizaram para resolver o problema de
importações cíclicas, e caso você tenha dependências cíclicas de módulos no seu programa, se
certifique de planejar corretamente para que elas funcionem como o esperado.
Módulos do núcleo do Node
O Node tem muitos módulos compilados em arquivos binários. Estes módulos estão
descritos em detalhes na documentação da API do Node - em Inglês.
Os módulos do núcleo (em Inglês core) estão dentro da pasta lib/ na raiz do Node.
O Node sempre dá preferência em carregar os módulos do núcleo se seu identificador é
passado para a função require() . Por exemplo require('http') irá sempre retornar o módulo
HTTP embutido no núcelo do Node, mesmo que tenha um arquivo com o mesmo nome nesta
pasta.
Arquivo dos Módulos
Caso o nome do arquivo passado para a função require() não for encontrado, então o Node
irá tentar carregar um arquivo com o nome passado adicionando a extensão ` .js, .json, e por
fim .node` .
Notar que arquivos ` .js são interpretados como arquivos de texto **JavaScript** e arquivos
.json são analisados como arquivos de texto **JSON**. Já arquivos .node são interpretados
como um módulo compilado carregado com dlopen` .
Um módulo com prefixo ` / ` será buscado no caminho absoluto sistema de arquivos. Por
exemplo, require('/home/node/exemplo.js') irá carregar o arquivo presente em `
/home/node/exemplo.js` .
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 124
Um módulo com prefixo ` ./ ` será buscado no caminho relativo ao módulo que chamou a
função require() . Como no exemplo apresentado, circulo.js deve estar no mesmo diretório de
calculo.js para que require('./circulo.js') encontre ele.
Já um módulo com prefixo ` ../ ` será buscado na pasta superior relativa ao módulo que
chamou a função require() .
Caso o módulo requisitado não contenha o prefixo ` / ` ou ` ./ ` para indicar a localização do
arquivo o módulo será considerado ou um módulo do núcleo ou um módulo instalado na pasta
node_modules, gerenciada pela NPM .
Agora se o caminho do arquivo não existir, require() vai emitir um Erro com sua propriedade
code igua a 'MODULE_NOT_FOUND' .
Carregando da pasta node_modules
Se o identificador passado para require() não é um módulo nativo, e não começa com ` / , ../
, ou ./ , então Node começa a buscar no diretório pai do módulo atual, e adiciona
/node_modules`, e espera carregar o módulo requisitado neste local. Se ele não for
encontrado lá, então ele move para o diretório pai do diretório atual, e assim sucessivamente,
até atingir o diretório raíz do sistema.
Por exemplo, se o arquivo ` /home/node/projetos/exemplo.js chamou
require(‘meu_modulo.js’)`, então o Node deve procurar nos seguintes locais, nesta ordem:
/home/node/projetos/node_modules/meu_modulo.js
/home/node/node_modules/meu_modulo.js
/home/node_modules/meu_modulo.js
/node_modules/meu_modulo.js
Pastas como Módulos
É conveniente organizar programas e bibliotecas dentro de seus diretórios independentes,
e então fornecer um único acesso para esta biblioteca. Há três maneiras que uma pasta pode
ser passada para a função require() como um argumento.
A primeira é criando um arquivo package.json na raíz da pasta, que especifica o módulo
principal - main - e um nome - name . Veja um exemplo do arquivo package.json a seguir:
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 125
{ "name" : "some-library",
"main" : "./lib/uma-biblioteca.js"}
Se este exemplo estivesse na pasta ` ./uma-biblioteca, então uma chamada require(‘./uma-
biblioteca’) tentaria carregar o arquivo ./uma-biblioteca/lib/uma-biblioteca.js` .
Caso não haja um arquivo package.json presente no diretório, então node tentaria carregar
um arquivo index.js ou index.node presentes neste diretório. Se no exemplo dado não existisse
o arquivo package.json, então uma chamada a require('./uma-biblioteca') tentaria carregar o
arquivo ` ./uma-biblioteca/index.js ou ./uma-biblioteca/index.node` .
Módulos salvos em Cache
Os módulos são salvos em Cache após a primeira vez que eles são carregados. Isto significa,
entre outras coisas, que toda chamada require('modulo') vai retornar exatamente o mesmo
objeto retornado na primeira chamada, se ela fosse importar o mesmo arquivo.
Múltiplas chamadas para require('modulo') não pode fazer com que o código do módulo
seja executado múltiplas vezes. Esta é uma característica importante. Com isso, objetos podem
ser retornados, permitindo assim que dependências transitivas possam ser carregadas mesmo
se elas causarem ciclos - isto é, tiverem importações cíclicas.
Caso você precise que um módulo execute um código várias vezes, então exporte uma
função contendo este código e faça chamadas para esta função.
Advertências para Módulos salvos em Cache
Um módulo é salvo no Cache baseado no seu endereço em disco, por exemplo `
/home/node/projetos/node_modules/meu_modulo.js . Uma vez que uma chamada para a
função require(‘meu_modulo’) faz uma busca pelo módulo em vários diretórios, seguindo a
sequência passada, caso ela encontre o módulo em uma pasta diferente da já salva em Cache,
por exemplo no diretório atual ./meu_modulo.js`, então o módulo será considerado um
módulo novo e não será usado a referência já salva em Cache.
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 126
O objeto module
Em cada módulo module é uma variável re referencia para o objeto que representa o
módulo atual. Em particular module.exports é acessível através do módulo global exports . O
objeto modulo na realidade não é global, mas um objeto local de cada módulo.
module.exports
O objeto module.exports é criado pelo sistema de módulos do Node e a variável exports
aponta para este objeto. Seu módulo pode retornar vários objetos e funções simplesmente
adicionando-os a variável export, por exemplo exports.falar = function(){ console.log('Bom
dia!') }; . Porém algumas vezes gostaríamos que nosso módulo retorne a instância de uma
classe. Atribua o objeto desejado para ser exportado em module.exports . Atenção, neste caso
não utilize a variável exports . Por exemplo suponha que estivéssemos fazendo um módulo
chamado a.js .
// a.js
var EventEmitter = require('events').EventEmitter;
module.exports = new EventEmitter();
// Executar algum trabalho, e apos algum tempo emitir
// o evento 'pronto' para o proprio modulo.
setTimeout(function() {
module.exports.emit('pronto');
}, 1000);
Então em outro arquivo nós poderíamos fazer:
// main.js
var a = require('./a');
a.on('pronto', function() {
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 127
console.log('O modulo a esta pronto!');
});
É importante saber que atribuições a module.exports devem ser feitas imediatamente, elas
não podem ocorrer em nenhum callback. O exemplo a seguir não irá funcionar.
// x.js
setTimeout(function() {
module.exports = { a: "Ola" };
}, 0);
// y.js
var x = require('./x');
console.log(x.a);
Um módulo Node tem variáveis disponíveis por padrão no escopo de cada módulo,
acompanhe a lista abaixo contendo as mais interessantes:
__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
process.argv: Um array contendo os argumentos de linha de comando. O primeiro elemento
será node, o segundo elemento será o nome do arquivo JavaScript, e os próximos serão todos
os argumentos de linha de comandos adicionais, caso sejam atribuídos
process.stdin, process.stout, process.stderr: Streams que correspondem à entrada padrão, a
saída padrão, e a saída de erro padrão do processo atual
process.env: Um objeto contendo as variáveis de ambiente do usuário do processo atual
require.main: Quando um arquivo é executado diretemente pelo Node, require.main é
atribuído à este module .
Execute o exemplo a seguir para que você acompanhar a utilização destas variáveis dentro
de um módulo, você pode executar o código abaixo salvando-o em um arquivo exemplo.js e
executando através da linha de comando node exemplo.js .
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 128
// exemplo.js
console.log('__filename: ', __filename);
console.log('__dirname: ', __dirname);
console.log('process.argv: ', process.argv);
console.log('process.env: ', process.env);
if(module === require.main) {
console.log('Este e o modulo principal sendo executado.');
}
Carregando seu módulo de pastas globais
Se a variável de ambiente NODE_PATH é definida com uma lista de caminhos absolutos
delimitados por dois pontos, então o node vai buscar nestes caminhos por módulos se eles não
forem encontrados em nenhum dos locais anteriormente buscados. Lembrando que no
Windows para definir uma variável de ambiente você deve acessar as propriedades do Meu
Computador, acessar Configurações avançadas do sistema e entrar nas Variáveis de Ambiente,
e para adicionar a variável NODE_PATH clique Novo…, adicione o nome da variável como
NODE_PATH e no valor da variável você pode inserir uma lista de caminhos absolutos
delimitados por ponto e virgula - no caso do Windows.
Adicionalmente, node vai buscar nas seguintes localizações:
$HOME/.node_modules
$HOME/.node_libraries
$PREFIX/lib/node
Onde $HOME é o diretório Home do usuário e $PREFIX é a configuração node_prefix do Node.
Estes são, em maior parte, por razões históricas. Sendo que você sempre será altamente
encorajado à colocar suas dependências localmente na pasta node_modules . Elas serão
carregadas mais rápido e com mais segurança.
Identificando o módulo principal
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 129
Quando um arquivo é executado diretamente no Node, require.main é definido como seu
module . Isso significa que você pode determinar quando um arquivo está sendo executado
diretamente fazendo o teste:
require.main === module
Para o exemplo apresentado principal.js, esta operação retornará true se executado
diretamente via node principal.js, porém retornará false se executado através de uma
importação require('./principal.js')
Pelo fato do objeto module fornecer a propriedade filename (normalmente equivalente à
variável global - diferente para cada módulo - __filemane), você também pode obter o
endereço do ponto de entrada da aplicação, o módulo principal, através da variável
require.main.filename .
Note que se você importar um módulo através do REPL do Node avariável require.main
naturalmente retornará undefined, porque não há um módulo principal sendo executado, e
sim a linha de comando do Node.
NPM
Não se pode falar em módulos em Node sem falar do NPM, ele é o gerenciador de pacotes
incluso dentro do pacote do Node. Não vou entrar neste artigo, mas vocês perceberão que ele
é fantástico e você deve usá-lo. Você pode ler mais neste artigo introdutório sobre a NPM e
neste outro artigo que fala mais sobre a NPM e como instalar pacotes utilizando ela.
Se você não está usando a NPM e os módulos do Node para implementar sua aplicação,
você pode estar fazendo isso errado!
– Modularizar: Escrever pequenos módulos que fazem apenas uma coisa, e integrá-los para
fazer coisas mais complexas – Usar o gerenciador de pacotes: Usar a NPM para administrar
suas dependências e parar de se preocupar com elas – Utilizar módulos em Node: É um
sistema de módulos simples e expressivo que facilita a modularização de sua aplicação em
Node e te proporciona módulos paramétricos de primeira classe
O que é a NPM do Node.JS
NPM é o nome reduzido de Node Package Manager (Gerenciador de Pacotes do Node). A
NPM é duas coisas: Primeiro, e mais importante, é um repositório online para publicação de
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 130
projetos de código aberto para o Node.js; segundo, ele é um utilitário de linha de comando
que interage com este repositório online, que ajuda na instalação de pacotes, gerenciamento
de versão e gerenciamento de dependências..
A NPM já conta com mais de 35 mil pacotes (Jul-2013), são bibliotecas e aplicações de
código aberto, e muitas são adicionadas todos os dias. Estas aplicações podem ser encontradas
através do portal de busca da NPM. Uma vez encontrado o pacote que você deseja instalar, ele
pode ser instalado com uma única linha de comando.
Digamos que você está trabalhando duro um dia para desenvolver sua Próxima Grande
Aplicação. Então você se depara com um problema e decide que está na hora de usar aquela
biblioteca legal que você tem ouvido a respeito - vamos usar a biblioteca assincrona de Coalan
McMahon como exemplo. Felizmente a NPM é muito simples de usar, você só precisa usar o
comando npm install async, e o módulo específico será instalado no diretório atual dentro da
pasta ./node_modules/. Uma vez instalada sua pasta node_modules, você será capaz de usar
require() nela como se fossem módulos internos do seu projeto. Para compreender melhor a
função require() eu aconselho que você leia o artigo que explica como funciona a função
require do Node.js.
Vamos ver um exemplo de pacote instalado globalmente - vamos falar do coffee-script. O
comando para o NPM é simples: npm install coffee-script -g. Para usuários do Linux este
comando irá instalar o progama e colocar um link simbólico (symlink) na pasta /usr/local/bin.
Isto permitirá você rodar o programa diretamente do console como qualquer outra ferramenta
CLI (Command-Line Interface). Neste caso, rodar o comando coffee te permitirá usar o REPL do
coffee script.
Outro importante uso da NPM é o gerenciamento de dependências. Quando você tem um
projeto Node com um arquivo package.json, você pode rodar o comando npm install na pasta
raiz do seu projeto e a NPM vai isntalar todas as dependências listadas no package.json. Isto
faz a instalação de projetos Node de repositórios Git muito mais fáceis! Vamos usar o exemplo
do vows, um dos frameworks de testes do Node, ele pode ser instalado através do Git, e suas
dependências: eyes, diff e glob podem ser automáticamente instaladas utilizando uma única
linha de comando da NPM.
Observe os comandos para clonar o projeto vows do github utilizando o git, e instalar suas
dependências listadas no arquivo package.json:
git clone https://github.com/cloudhead/vows.git
cd vows
npm install
Após rodar estes comandos, você vai ver a pasta node_modules contendo todas as
dependências especificadas no package.json.
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 131
Como usar o util.inspect em NodeJS
O NodeJS fornece uma útil função para propósitos de debugação que retorna uma
representação em texto de um objeto. util.inspect pode ser um salva-vidas ao se trabalhar
com propriedades de objetos grandes e complexos.
O módulo util do NodeJS contém uma série de métodos utilizados para formatar texto,
debugar, imprimir mensagens no console, checar objetos (util.isArray(objeto),
util.isRegExp(objeto), util.isDate(objeto) e util.isError(objeto)) e um método de herança
(util.inherits(construtor, superConstrutor)). Neste artigo veremos o método util.inspect.
A seguir há um exemplo simples, util.inspect pode ser usado com qualquer objeto e uma
boa demonstração pode ser usá-lo nos objetos embutidos do Node. Tente o código abaixo no
REPL do Node. Caso você não conheça o REPL, ou não saiba como acessá-lo, eu te aconselho a
ler nosso artigo explicando como usar o REPL do Node.
> var util = require('util')
undefined
> util.inspect(console)
'{ log: [Function],\n info: [Function],\n warn: [Function],\n error: [Function],\n dir:
[Function],\n time: [Function],\n timeEnd: [Function],\n trace: [Function],\n assert:
[Function] }'
Como você pode se recordar, a cada comando passada para o REPL ele imprime o retorno
do comando. O que nos interessa aqui é o retorno do comando util.inspect(console) que pode
ser visto na linha abaixo deste comando. Podemos ver que o comando nos retornou uma
string contendo todas as funções enumeráveis deste módulo.
Então nós sabemos que a função util.inspect retorna uma string contendo as propriedades
enumeráveis de qualquer objeto e também é válido acrescentar que a função console.dir é um
envólucro em torno de util.inspect, utilizando seus argumentos padrões e imprimindo seu
retorno na tela. Ao se imprimir o retorno do util.inspect utilizando a função console.log o
console utilizará a formatação contida na string, como a quebra de linhas e a exibição de cores.
> console.log(util.inspect(console))
{ log: [Function],
info: [Function],
warn: [Function],
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 132
error: [Function],
dir: [Function],
time: [Function],
timeEnd: [Function],
trace: [Function],
assert: [Function] }
undefined
util.inspect pode também ser passada com vários argumentos opcionais, apresentados aqui
com seus valores padrões:
util.inspect(object, showHidden=false, depth=2, colors=false, customInspect=true);
Por exemplo, util.inspect(meuObjeto, true, 7, true, false) poderia inspecionar meuObjeto,
mostrando todos as propriedades ocultas e não ocultas até a profundidade 7, colorir a saída e
a função inspect() definida no objeto não será chamada.
O argumento opcional depth (profundidade em inglês) é o número de níveis de
profundidade de um objeto que será feita a recursão, seu valor padrão é 2. Isso é útil para
objetos grandes e complicados. Definindo este valor como null vai forçar a recursão até atingir
o último nível de profundidade. Para observar seu comportamento você pode inserir os
comandos a seguir no REPL do Node.
var http = require('http');
console.log(util.inspect(http, false, 1));
console.log(util.inspect(http, false, 2));O argumento opicional showHidden é um booleano que determina se vai ou não exibir as
propriedades não-enumeradas de um objeto, seu valor padrão é false o que tende a resultar
em saídas muito mais legíveis. Isso não é algo que um iniciante deve se preocupar na maior
parte do tempo, mas é válido demonstrar rapidamente. Você poderá perceber a diferença
executando os comandos a seguir no REPL do Node.
console.log(util.inspect(console, false, 1))
console.log(util.inspect(console, true, 1))
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 133
O argumento opicional color também é um valor booleano que diz se a função deve, ou
não, decorar a string de saída com códigos de cores ANSI, as cores são customizáveis.
Basicamente ela faz com que, na janela do terminal, a string de retorno possa ser impressa em
cores. Faça o teste utilizando o comando a seguir.
var util = require('util');
console.log(util.inspect(console, false, 2, true));
Módulos do Núcleo do Node
Primeiro eu recomendo que uma versão do node esteja instalada no seu computador. Um
modo fácil para que isso aconteça e visitando nodejs.org e clique em Install.
Node tem um pequeno grupo de módulos que vem com ele por padrão (comumente
chamados como ‘núcleo do node’) eles são representados por suas API’s publicas e você utiliza
elas para escrever os seu programas. Para trabalhar com sistema de arquivos existe o módulo
fs e para redes os módulos são net (TCP), http, dgram (UDP).
Em adição ao fs e os módulos de rede existem outros módulos na base do núcleo do node.
Lá também temos um modulo assincrono para resolver consultas de DNS chamado dns, um
módulo para pegar informações especificas do sistema, por exemplo o tmpdir e ele chama os,
um outro para alocação de pedaços de binários na memória chamado buffer, varios módulos
para análise de urls e caminhos (url, querystring, path) entre outros. A maioria dos módulos
presentes no núcleo do node suportam os principais casos de uso dele: escrever rapidamente
programas que conversem com os sistema de arquivos ou rede.
Node lida com I/O com: callbacks, eventos, streams e módulos. Se você aprende como
essas quatro coisas trabalham vocês esta habil para ir em quanlquer módulo do core do node a
ter um entendimento básico sobre como a interface funciona com ele.
Evoluindo de Forma Granular em Node
Como todo boa ferramenta, o Node é bem adequado para certos casos de uso. Por
exemplo: Rails, o popular web framework, é ótimo para modelar complexas lógicas de
negócio, ex. usando código para representar a vida em um plano objetivado que vivemos
físicamente como contas, empréstimos, itinerários e inventários. Embora técnicamente seja
possível fazer o mesmo utilizando o Node, haveria desvantagens claras sabendo que o Node é
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 134
projetado para resolver problemas de I/O e não saber sobre a parte da ‘lógica de negócio’.
Cada ferramenta tem seu foco voltado a resolver diferentes problemas. Esperamos que este
guia ajude-o a ganhar uma compreensão intuitiva dos pontos fortes do Node e você saberá
quando ele será útil.
O que está fora do escopo do Node?
Fundamentalmente o Node é somente usado como ferramenta para gerenciar I/O ao
redor do sitema de arquivos e redes, ele deixa outras funcionalidades mais bonitas com
módulos de terceiros. Estas são algumas das coisas fora do escopo do Node:
Web frameworks
Existem uma boa quantidade de web frameworks construidos em cima do Node
(framework é um pacote que tenta resolver um problema de alto nível e problemas similares
ao modelar a lógica de negócio), mas o Node não é um framework para web. Frameworks web
são escritos para serem utilizado no Node e nem sempre tomam o mesmo tipo de decisões
sobre a adição de complexidade, abstração e compreensão que o Node faz e podem ter outras
prioridades.
Sintaxe da linguagem
O Node usa JavaScript e não muda nada sobre isso. Felix Geisendörfer tem um belo
conteúdo escrito sobre o ‘estilo de escrita do Node’ aqui.
Abstração da linguagem
Quando possível o Node vai usar a maneira mais simples de escrever algo. Código mais
‘bonito’ faz do seu JavaScript mais complexo e compromissado com vantagens e desvantagens.
Programar é difícil, especialmente em JS onde você tem 1000 soluções para o mesmo
problema! Essa é a principal razão para o Node optar pela simplicidade sempre que possível e
que pode ser uma opção universal. Se você está resolvendo um problema complexo e você
está insatisfeito com o modo que o Node implementa as coisas com soluções originais do JS,
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 135
sinta-se livre para resolver isso dentro do seu app ou módulo usando quaisquer abstrações que
você preferir.
Um grande exemplo de como o Node usa os callbacks. Logo no início foi experimentado a
caracteristica chamada ‘promessas’ que adiciona algumas funcionalidades para fazer o código
assíncrono parecer mais linear. Ele foi levado para o fora do núcleo do Node por algumas
razões:
eles são mais complexos que callbacks
ele podem ser implementados na userland (distriuído no npm como módulo de terceiros)
Considerando uma das mais universais e básicas ideias que o Node faz: ler um arquivo.
Quando você lê um arquivo e precisa saber onde os erros acontecem, como exemplo quando o
disco rígido morre no meio da sua leitura. Se você tem promessas tudo que você terá é um
código como esse:
fs.readFile('movie.mp4')
.then(function(data) {
// faça algo com os dados
})
.error(function(error) {
// lide com o erro
})
Isso adiciona uma complexidade, desnecessária. No lugar de duas funções separadas o
Node somente usa uma única função de callback. Aqui temos as regras:
Quando não existir erros passe null como primeiro argumento
Quando o existir erro, passar ele como primeiro argumento
O restante dos argumentos são usados para qualquer coisa (usualmente dados ou
respostas já que na maior parte do tempo o Node está lendo ou escrevendo coisas)
Por isso, o Node usa o estilo de callback:
fs.readFile('movie.mp4', function(err, data) {
// lide com o erro, e faça algo com os dados
})
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 136
Eventos em Node
No node com o módulo de eventos você pode disparar eventos, também chamando de
‘emissor de evento’, até mesmo o node usa em todas as suas APIs para emitir coisas.
Eventos são padrões comuns de programação, para conhecer melhor procure por ‘observer
pattern’ ou ‘pub/sub’ (publicar/assinar). Ao passo que callbacks são uma relação um-para-um
entre algo que espera pelo callback e outra parte que chama o callback, eventos seguem o
mesmo padrão com exceção de que eles são uma API de muitos-para-muitos.
Aqui temos casos comuns de uso dos eventos ao invés de simples callbacks:
Uma sala de chat onde você tem um canal de mensagens com muitos ouvintes.
Servidor de um jogo que necessita saber quando os players se ligam, desligam, movem-se,
atiram ou pulam
Conectores de bancos de dados podem precisar saber onde suas conexões estão abertar,
fechadas ou enviando umerro.
Se você tentar escrever um servidor de chat que se conecte usando apenas callbacks ele
irá parecer com isso:
var chatClient = require('my-chat-client')
function onConnect() {
// exibe a UI quando conectar-se
}
function onConnectionError(error) {
// exibe erros para o usuario
}
function onDisconnect() {
// avisa ao usuario que ele foi desconectado
}
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 137
function onMessage(message) {
// exibe a mensagem na UI da sala
}
chatClient.connect(
'http://mychatserver.com',
onConnect,
onConnectionError,
onDisconnect,
onMessage
)
Como você pode ver é realmente pesado escrever porque você tem que passar todas as
funções em uma ordem especifica para a função .connect. Escrevendo isso com eventos irá se
parecer com isso:
var chatClient = require('my-chat-client').connect()
chatClient.on('connect', function() {
// exibe a UI quando conectar-se
})
chatClient.on('connectionError', function() {
// exibe erros para o usuario
})
chatClient.on('disconnect', function() {
// avisa ao usuario que ele foi desconectado
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 138
})
chatClient.on('message', function() {
// exibe a mensagem na UI da sala
})
Esta abordagem é bastante similar a utilização com callbacks-puros mas essa abordagem
introduz o método .on, onde é atrelado um callback ao evento. Isso significa que você escolhe
o que tem que estar assinado para chatClient. Você é capaz de assinar o mesmo evento várias
vezes com diferentes callbacks:
var chatClient = require('my-chat-client').connect()
chatClient.on('message', logMessage)
chatClient.on('message', storeMessage)
function logMessage(message) {
console.log(message)
}
function storeMessage(message) {
myDatabase.save(message)
}
Mais conteúdo sobre eventos em Node está por ser escrito ainda no livro…
Entendendo o Node
Node.js é um projeto de código aberto projetado para auxiliar na escrita de programas em
JavaScript que conversem com redes, sistema de arquivos ou outro I/O (entrada/saida,
leitura/escrita). É isso o que ele é. Ele é uma simples e estável plataforma de I/O que encoraja
você a escrever módulos para funcionar nele.
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 139
Quais são alguns exemplos de I/O? Bom… aqui tem um diagrama de uma aplicação que eu
fiz com node e ela mostra várias fontes de I/O:
Se você não entende todas as diferentes coisas que estão nesse diagrama, fique tranquilo.
O ponto é, mostrar um unico nó de processo (o hexagono no meio) pode agir como o corredor
entre todos os diferentes pontos finais de I/O (laranja e roxo representam I/O).
Normalmente na construção desses sistemas temas as seguintes situações:
Dificuldade de programar, mas tem um super rendimento com resultados rápidos (igual
escrever servidores web do zero em C).
Facil de programar mas não é o ideal em relação a velocidade/robustez (semelhando ao
caso de tentar o upload de um arquivo de 5GB e o seu servidor quebrar)
A meta do Node é acertar o balanço entre estes dois: relativamente simples de entender e
usar rápido o suficiente para mais casos de uso.
Node não é o tanto dos seguintes itens:
Um web framework (semelhante ao Rails ou Django, que são utilizadas para certos tipos de
coisas)
Uma linguagem de programação (ele usa JavaScript mas o node não é uma linguagem)
Em vez disso, node é em algum lugar no meio. Assim:
Projetado para ser simples e portanto relativamente simples de entender o uso
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 140
Normalmente para programas baseados em I/O que precisam ser rápidos e/ou lidar com
muitas conexões
No baixo nivel, node é descrito como uma ferramente para escrever os seguintes dois
maiores tipos de programas:
Programas de reder ustilzando protocolos como: HTTP, TCP, UDP, DNS e SSL.
Programas de leitura e escrita de dados para o arqivos do sistema ou processes/memôria local.
O que é um programa baseado em “I/O”? Aqui estão os pontos comuns do I/O:
Bancos de dados (ex. MySQL, PostgreSQL, MongoDB, Redis, CouchDB).
APIs (ex. Twitter, Facebook, Apple Push Notifications).
Conexões HTTP/WebSocket (de usuários de um aplicativo web).
Arquivos (redimensionamento de imagem, editor de videos, rádio online).
Node faz o I/O de forma assíncrona asynchronous para lidar com diferentes situações
simultaneas. Por exemplo, se você vai até um fast food e faz o pedido de um cheesebuger você
tem de imadiato o pedido feito mas não o lanche, então você espara ele ficar pronto para
comer. Neste meio tempo outros pedidos estão sendo feitos na lanchonete para outras
pessoas. Imagine que você tenha que esperar o registro do seu cheeseburger, bloqueando
outras pessoas porque o seu pedido tem que ser feito para o de outra começar enquanto
preparam o seu. Isso é chamado de I/O bloqueante porque todo o I/O (cozinhar
cheeseburgers) acontece um a um enfileirando tudo. O Node, por sua vez é não-bloqueante,
significando que os pedidos serão feitos e entregues quando estiverem prontos.
Aqui tem uma lista de coisas divertidas que podem serem feitas com graças ao node por sua
natureza não bloqueante:
Controle quadicopteros voadores
Escrever bots par ao chat IRC
Criar robôs bipedes que andam
Callbacks em Node
É um dos tópicos mais importantes para se entender se você tem que entender como
utilizar o node. Quase tudo no node usa callbacks. Eles não foram inventados para o node,
somente tem um uso particular com funções do JavaScript.
Callbacks são funções que serão executadas de modo assincrono, ou posteriormente. Ao
passo que o código for lido de cima para baixo de modo processual, programas assincronos
possivelmente executam funções em tempos diferentes baseado na ordem e velocidade em
que requisições http ou o trabalho de arquivamento do sistema acontecem.
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 141
A diferença pode ser confusa sendo determinada quando uma função é assincrona ou não
depende da execução de um grande contexto. Seque um simples exemplo de código
assincrono:
var myNumber = 1
function addOne() { myNumber++ } // define a função
addOne() // executa a função
console.log(myNumber) // mostra na saida padrão o numero 2
O código acima define uma função e na linha seguinte chama essa função, sem esperar por
nada. Onde ela é chamada imediatamente adicionando 1 a váriavel myNumber, então depois
que a função foi chamada você espera que o numero seja 2 na váriavel myNumber.
Supondo que precisamos armazenar nosso numero em um arquivo chamado number.txt:
var fs = require('fs') // require é uma função especial do node para requisitar os módulos
var myNumber = undefined // não sabemos ainda qual valor esta armazenado no arquivo
function addOne() {
fs.readFile('./number.txt', function doneReading(err, fileContents) {
myNumber = parseInt(fileContents)
myNumber++
})}
addOne()
console.log(myNumber) // mostra na saida padrão `undefined`
Porque é que temos undefined quando pedimos para mostrar o numero dessa vez? Nesse
código usamos o método fs.readFile, que acontece de módo assincrono. Usualmente você tem
que se comunicar com os discos rigidos ou redes bem de modo assincrono. Se for somente
para acesso a memória ou fazer algo na CPU isso é feito bem de modo sincrono. A razão pela
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 142
qual fazer o I/O assincrono é porque o acesso ao disco é 100,000 vezes mais devagar do que
comunicar-se com a memória (RAM).
Onde você executa um programa onde as funções são imediatamente definidas, mas não
executa elas imediatamente. Este é um conceito fundamental para entender sobre a
programação assincrona. Onde addOne é chamada fora de fs.readFile e move-se para a
proxima tarefa pronta para ser executada e não esperar o disco responder igual a fs.readFile.
Se não tem nada para executar o node espera por pendências de operações fs/network
terminarem ou pararem de executar saindo da linha de comando.
Onde fs.readFile esta completa para ler o arquivo (talves isso demore millisegundos ou
segundos e até mesmo minutos dependendo de quanto o disco é rápipdo) executando a
função doneReading e dando um erro (claro que se algum tipo de erro acontecer) e o
conteúdo do arquivo.
A razão pela qual undefined foi mostrado no código acima é que ele é chamado dentro de
console.log e fora de fs.readFile mostrando o valor anterior de myNumber e não o conteúdo
do arquivo.
Se você tem um pedaço de código que precisa ser executado várias e várias vezes ou um
tempo depois, o primeiro passo é colocar esse pedaço de código dentro de uma função. Aonde
você podera chamar sem precisar escrever ele em todas as partes que for necessário e
nomeando da meneira que fique claro aquilo que esta sendo feito. Isso ajuda a dar nomes
descritivos para as funções.
Callback são somente funções que são executadas de forma tardia. A chave para a
compreensão de callbacks é perceber que eles são utilizados quando você não sabe quando
alguma operação assincrona estará completa, mas você sabe quando se completará - a ultima
linha da função assincrona! A ordem de cima-para-baixo que você declara para callbacks isso
não é necessariamnete importante, somente a ordem lógica/hierárquica de assentamento do
código. Primeiro divida o código em funções e use callbacks para declarar se uma depende da
outra função para encerrar.
O método fs.readFile é fornecido pelo node no módulo fs, é assincrono e acontece quando
se tem um tempo curto para finalizar. Considerando o que ele faz: ele vai até o sistema
operacional, que por sua vez esta rodando em um disco rígido isso pode ou não estar girando a
milhares de rotações por minuto. Então ele tem que usar o lazer para ler os dados e enviar
atráves das camadas de comunição do sistema de volta para o seu programa em javascript.
Você da ao fs.readFile uma função (conhecida como callback) que sera chamada depois de
recuperar os dados do sistema de arquivos. Ela coloca os dados recuperados em uma variavel
do javascript e passa para sua função (callback) com essa variavél, neste caso a variavel se
chama fileContents porque ela contém o conteúdo do arquivo que foi lido.
Pense no restaurante do exemplo do tutorial lá do inicio. Em muitos restaurantes você pega
um número e coloca em sua mesa e espera por sua comida. Eles são como os callbacks. Isso
deixa claro para o servidor a quem chamar quando o cheeseburger estiver pronto.
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 143
Colocando console.log em uma função e passando ele para um callback.
var fs = require('fs')
var myNumber = undefined
function addOne(callback) {
fs.readFile('./number.txt', function doneReading(err, fileContents) {
myNumber = parseInt(fileContents)
myNumber++
callback()
}
}
function logMyNumber() {
console.log(myNumber)
}
addOne(logMyNumber)
Agora a função logMyNumber que é passada como argumento se torna a variavél callback
dentro da função addOne. Depois que fs.readFile terminar a variavél callback é chamada
(callback()). Somente funções podem ser chamadas, então se você passar qualquer outra coisa
diferente de uma uma função, causará um erro.
Onde uma função é chamada no javascript o código dentro dessa função é imediatamente
executado. Neste caso nosso log é executado onde callback é atualmente a função
logMyNumber. Lembre-se, somente se você definiu uma função não significa que ela será
executada. Você tem que chamar uma função para ela acontecer.
Para quebrar esse exemplo em mais pedaços, aqui tem uma linha do tempo de eventos que
acontecem quando o seu programa é executado:
1: o código é analisado, isso significa que se existir algum erro de sintaxe o pragrama quebrará
e será apontado aonde isso aconteceu.
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 144
2: addOne será chamado, onde logMyNumber será passado com uma função chamada
callback, que é o que precisa ser chamado quando addOne estiver completa. Imediatamante
disparando o método assincrono fs.readFile. Essa parte do programa leva um tempo para
terminar.
3: com nada para fazer, o node espera por um tempo até o fs.readFile encerrar a sua
execução.
4: fs.readFile termina e chama o callback, doneReading, que incrementa o numero e
imediatamente chama a função logMyNumber contida na variável callback.
Talves a parte mais confusa de se programar com callbacks é que as funções são somente
objetos armazenados em variáveis e passadas em todo o programa com diferentes nomes.
Dando nomes simples e descritivos para suas variáveis faz seu código ser mais legível para
outros. Geralmente falando em programas no node onde você enxerga uma variável como
callback ou cb você assume ela como uma função.
Você talves tenha escutado alguns termos como programação evencionada ou ciclo de
eventos. Onde é referenciado da mesma maneira que fs.readFile foi implementada. Node
primeiramente despacha a operação fs.readFile e espera por fs.readFile enviar um evento para
concluir. Equanto a resposta é esperada o node vai buscando checar outras coisas. Dentro do
node há uma lista de coisas a serem feitas mas não informaram ainda, então o ciclo do node
acaba e retorna para a lista várias vezes checando se o que estava sendo processado terminou.
Depois do termino ele pega o que foi ‘processado’, ex. callbacks que dependem desse termino
são chamados.
Aquie temos uma versão de um pseudocódigo do exemplo acima:
function addOne(thenRunThisFunction) {
waitAMinute(function waitedAMinute() {
thenRunThisFunction()
})
}
addOne(function thisGetsRunAfterAddOneFinishes() {})
Imagine que tenha 3 funções assincronas a, b e c. Para cada uma leva-se 1 minuto de
execução e depois de terminado elas chamam um callback (que é passado como primeiro
argumento). Se você tem que falar para o node ‘comece executando a, depois b depois que a
terminar, e executar c então b termina’ isso passa a ser:
a(function() {
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 145
b(function() {
c()
})
})
Onde essecódigo será executado, a é imediatamente executado, um minuto depois que ele
teminar e chama b, outro minuto depois que ele teminar e chamar c e finalmente depois que 3
minutos se passaram o node para de executar desde que não tenha mais nada para fazer. Isso
é definitivamente a maneira mais elegante para escrever o código acima, mas o ponto é esse,
se você tem esse código que espera por uma porção de código assincrono terminar, onde é
expressado essas dependencias colocando seu código em funções, isso é passado às outras
funções como callbacks.
A projeção do node requer que você pense de modo não-linear. Considerando essa lista de
operações:
ler um arquivo
processar um arquivo
Se você ingênuamente transforma-se isso em um pseudocódigo você teria este resultado:
var file = readFile()
processFile(file)
Esse tipo de linearidade no código (passo-a-passo, em ordem) não é o modo como o node
trabalha. Se esse código fosse executado onde readFile e processFile estão sendo chamados ao
mesmo tempo. Não faria o menor sentido porque readFile leva um tempo para completar sua
execução. Ao passo que você precisa expressar processFile que depende do readFile completo.
Esta a exata finalidade dos callbacks! E por causa da forma que o JavaScript trabalha você pode
escrever dependencias de diferentes maneiras:
var fs = require('fs')
fs.readFile('movie.mp4', finishedReading)
function finishedReading(error, movieData) {
if (error) return console.error(error)
// faça algo com os dados em movieData
}
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 146
Mas você támbem pode estruturar o código dessa maneira que irá funcionar:
var fs = require('fs')
function finishedReading(error, movieData) {
if (error) return console.error(error)
// faça algo com os dados em movieData
}
fs.readFile('movie.mp4', finishedReading)
Ou até mesmo assim:
var fs = require('fs')
fs.readFile('movie.mp4', function finishedReading(error, movieData) {
if (error) return console.error(error)
// faça algo com os dados em movieData
})
Depurando (Debugando) Node.js com o Depurador embutido.
Se a versão web do seu aplicativo está funcionando, porém a versão de linha de comando está
dando erro. O que está acontecendo de errado? Pode ser difícil de descobrir. Se a aplicação
simplesmente terminou sem imprimir nada. Seus try/catch e manipuladores de evento não
identificaram nenhum erro e a típica abordagem por console.log() não imprime nada. Então o
melhor a se fazer é usar o depurador do Node.js para fazer a depuração do seu código. Uns até
falam debugar o código, debugar é uma palavra derivada da palavra em Inglês debugging (ou
simplesmente debug).
O motor V8 da Google, onde o Node roda, vem com um extenso depurador acessível via
protocolo TCP e o Node.js tem um cliente embutido para este depurador. Este é considerado o
depurador (cliente de depuração) do Node. Este artigo ensina como usar o depurador do Node
para depurar seu script expondo como colocar pontos de interrupção (breakpoints), rodar o
REPL do Node no meio da depuração, percorrer pelo código e analizar as saídas do depurador.
O básico
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 147
O motor V8 da Google tem um depurador embutido e o Node tem um cliente para acessar
este depurador
O depurador pode ser iniciado usando executando o node com o argumento debug
Na sua aplicação você pode definir pontos de interrupção usando a palavra reservada
debugger
Você pode adicionar vigilantes para acompanhar o valor de expressões durante a depuração
Agora vamos a cada etapa da debugação.
Inserindo alguns pontos de interrupção
Um ponto de interrupção (breakpoint) é um lugar em seu codigo onde você deseja que sua
aplicação pare momentaneamente para que você possa analisar o estado do seu programa
naquele ponto do código. Se você não usar um ponto de interrupção você vai ter percorrer o
código passo-a-passo até chegar onde você deseja depurar.
Então, basicamente, seu script você vai precisar colocar alguns pontos de interrupção em
lugares próximos onde você acha que o seu sistema esteja se comportando de maneira
indevida. Acompanhe o exemplo depurar.js apresentado abaixo.
x = 5;
setTimeout(function () {
debugger; // Ponto de interrupcao
console.log("mundo");
}, 1000);
console.log("Ola");
O ponto de interrupção é adicionado no código usando a palavra reservada debugger. Este é
um acessório do motor V8, não necessariamente do Node.js.
Você pode setar muitos pontos de interrupção no seu código se você precisar.
Iniciando o depurador
Para iniciar o depurador, rode seu script usando o argumento debug do node, no nosso
exemplo: node debug depurar.js. Você vai ser levado ao REPL do depurador debug > e então
você vai poder usar o comando help para ver a lista de comandos disponíveis e começar e
debugar seu código. Quando você abre o depurador seu inicia pausado na primeira linha e
você precisa usar o comando cont para rodar seu código até ser interrompido quando o
depurador encontrar a palavra reservada debugger ou você usar o comando pause.
$ node debug depurar.js
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 148
< debugger listening on port 5858
connecting... ok
break in /home/rafadev/git/depurador/depurar.js:1
1 x = 5;
2 setTimeout(function () {
3 debugger;
debug> cont
< Ola
break in /home/rafadev/git/depurador/depurar.js:3
1 x = 5;
2 setTimeout(function () {
3 debugger;
4 console.log("mundo");
5 }, 1000);
debug> next
break in /home/rafadev/git/depurador/depurar.js:4
2 setTimeout(function () {
3 debugger;
4 console.log("mundo");
5 }, 1000);
6 console.log("Ola");
debug> repl
Press Ctrl + C to leave debug repl
> x
5
> 2+2
4
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 149
debug> next
< mundo
break in /home/rafadev/git/depurador/depurar.js:5
3 debugger;
4 console.log("mundo");
5 }, 1000);
6 console.log("Ola");
7
debug> quit
O comando next avalia a próxima linha do seu código e o comando repl permite você avaliar o
estado atual do seu programa remotamente através do REPL do Node. Há também outros
comandos disponíveis, lembrando que você pode digitar help para lembrar dos comandos
disponíveis.
Listagem de código e gerando um rastreamento
A primeira coisa que você possívelmente vai fazer é se orientar. Onde, exatamente, nós
estamos no código? Para fazer isso use a função list. Esta função imprime um segmento
formatado do código de onde você está. Esta função recebe como parâmetro um número
dizendo quantas linhas de contexto serão impessas. Exemplo de uso: list(2) vai imprimir onde
você está mais as 2 linhas anteriores e as 2 posteriores.
debug> list(2)
3
4 setTimeout(function () {
5 debugger;
6 console.log("mundo");
7 }, 1000);
Aqui nós podemos ver o contexto da linha corrente que o programa se encontra, então
podemos saber aonde o programa encontra-se pausado. O próximo comando a ser avaliado
estará marcado com a cor verde, neste exemplo a palavra debugger está em verde.
Vigilantes (Watchers)
[NODE.JS UMA NOVA ABORDAGEMDA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 150
Você pode vigiar o valor de uma expressão ou de uma variável enquanto depura seu código.
Em cada ponto de interrupção os vigilantes serão avaliados no contexto atual e seus valores
serão impressos logo depois da origem da interrupção.
Para começar a vigiar uma expressão, insira watch("sua_expressao"). O comando watchers
imprime os vigilantes ativos. Para deixar de vigiar uma expressão, insira
unwatch("sua_expressao").
Movimentação com next, step e out
O comando next, como já foi dito, prossegue a execução do programa avaliando a linha a atual
e pausando na primeira expressão da próxima linha. Caso a linha a ser avaliada faça referência
a algum método de outro módulo, ou até mesmo do core, você também pode depurar o
funcionamento interno deste método, basta utilizar a função step que é o abreviamento para
“step into this one” que pode ser traduzido para “entrar neste” que basicamente entra para
depurar o método internamente.
Quando você está depurando internamente o funcionamento deste método, você pode ir
utilizando os comandos next e step para rastrear com detalhes o que está ocorrendo “por trás
dos panos” depurando até o próprio core do Node, caso você deseje. Já o comando out serve
para você voltar para o código que chamou aquele método e pausar para a próxima expressão.
Lista de Comandos
Movimentação
cont, c - Continuar a execução
next, n - Próximo passo
step, s - Entrar
out, o - Sair
pause - Pausar a execução de um código (como o botão de pausar nas ferramentas de
desenvolvimento)
Pontos de interrupção
setBreakpoint(), sb() - Setar um ponto de interrupção na linha corrente
setBreakpoint(linha), sb(linha) - Setar um ponto de interrupção em uma linha específica
setBreakpoint('fn()'), sb(...) - Setar um ponto de interrupção na primeira instrução no corpo da
função
setBreakpoint('script.js', 1), sb(...) - Setar um ponto de interrupção na primeira linha do
script.js
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 151
clearBreakpoint, cb(...) - Remover um ponto de interrupção
Também é possível inserir um ponto de interrupção em um arquivo (módulo) que ainda não
foi carregado, por exemplo usando o comando setBreakpoint('mod.js', 23) adiciona um ponto
de interrupção no módulo mod.js na linha 23.
$ node debug main.js
< debugger listening on port 5858
connecting to port 5858... ok
break in /home/rafadev/git/depurador/main.js:1
1 var mod = require('./mod.js');
2 mod.hello();
3 mod.hello();
debug> setBreakpoint('mod.js', 23)
Warning: script 'mod.js' was not loaded yet.
1 var mod = require('./mod.js');
2 mod.hello();
3 mod.hello();
debug> c
break in /home/rafadev/git/depurador/mod.js:23
21
22 exports.hello = function() {
23 return 'hello from module';
24 };
25
debug>
Informação
backtrace, bt - Imprime um registro de chamadas do quadro atual de execução
list(5) - Lista o código fonte do script com 5 linhas de contexto (5 linhas antes e 5 depois)
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 152
watch(expr) - Adiciona uma expressão para a lista vigiada
unwatch(expr) - Remove uma expressão da lista vigiada
watchers - Lista todos os vigiados e seus valores (atumaticamente listado em cada ponto de
interrupção)
repl - Abre o REPL de debugação para avaliação no contexto de depuração do script
Controle de execução
run - Executa o script (é automaticamente executado quando o depurador é iniciado)
restart - Reinicia um script
kill - Mata um script
Diversos
scripts - Lista todos os scripts carregados
version - Imprime a versão da engine V8
Vantagens de uso
O depurador da V8 pode ser abilitado e acessado tanto iniciando o Node com o sinalizador
(flag) de linha de comando --debug como sinalizando um processo existente em Node com
SIGUSR1.
Uma vez que o processo foi colocado em modo de depuração dessa forma ele pode ser
conectado pelo depurador do node. Tanto conectado pelo pid quanto pelo URI para o
depurador. A sintaxe é:
node debug -p <pid> - Conecta com o processo via pid
node debug - conecta com o processo via URI tal como localhost:5858
Primeiros passos com Passport e Express em Node.js
Passport é um middleware para Node.js que faz a implementação de autenticação em um
aplicativo de maneira rápida e fácil. Em aplicações web modernas podem-se ter várias formas
de autenticação. Tradicionalmente usuários se logam fornecendo um usuário e uma senha.
Com o crescimento das redes socieais, logar-se com um provedor OAuth como o Facebook ou
o Twitter tem se tornado métodos populares de autenticação.
Passport reconhece que cada aplicação tem requisítos únicos de autenticação. Mecanismos de
autenticação, conhecidos como estratégias, são empacotados como módulos individuais. As
aplicações podem escolher qual estratégia empregar sem criar dependências desnecessárias.
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 153
Sabendo que muitos usuários preferem se logar utilizando uma já conta existente em uma
rede social, como o Facebook ou Twitter. Neste exemplo vai ser implementado o suporte para
o usuário se logar com a sua conta do Twitter.
Instalando as dependências
$ npm install express
$ npm install passport
$ npm install passport-twitter
$ npm install connect-ensure-login
O exemplo consiste em uma aplicação Express simples, baseada na aplicação desenvolvida
passo a passo do artigo anterior, então para melhor acompanhamento se certifique de ter
compreendido os conceitos básicos já apresentados.
Passport tem uma arquitetura modular que quebra o mecanismo de autenticação em
estratégias (neste caso do Twitter) que são distribuídas separadamente, mantendo o núcleo
leve. Também será usado o connect-ensure-login para proteger rotas exclusivas para usuários
logados.
Checklist da autenticação
São necessários verificar três itens para implementar a autenticação.
Configurar o middleware de sessão
Configurar as estratégias de autenticação
Adicionar as rotas de autenticação
Estes tópicos serão detalhados a seguir, começando por: rotas para o middleware.
Rotas para autenticação
Vamos adicionar rotas para /account, que mostra para a pessoa detalhes da conta.
app.get('/account',
ensureLoggedIn('/login'),
function(req, res) {
res.send('<html><body>Ola '+ req.user.username+'.<br/><a
href="/logout">Logout</a></body></html> ');
});
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 154
Para acessar esta página o usuário terá que estar logado, ensureLoggedIn vai verificar isso, e
caso ele não esteja logado, redireciona o usuário para a página de login. Que é implementada
a seguir.
app.get('/login',
function(req, res) {
res.send('<html><body><a href="/auth/twitter">Login com Twitter</a></body></html>');
});
Simples assim. O usuário pode clicar no link e se logar com sua conta do Twitter. O que nos
leva à próxima etapa da nossa implementação:
Configurar a autenticação do Twitter
A autenticação do Twitter usa o padrão de autorização OAuth, que significa que você vai
precisar obter uma chave (key) e uma chave secreta (secret) do Twitter. Se você não tem uma
ainda, você vai precisar registrar suaaplicação no Twitter. Para nosso que nosso exemplo
funcione em seu servidor local, você pode completar o campo Website com
http://127.0.0.1:3000/ e o campo Callback URL com
http://127.0.0.1:3000/auth/twitter/callback.
Uma vez que você tenha as chaves, configure a estratégia de autenticação do Twitter assim:
var TWITTER_CONSUMER_KEY = "INSIRA_SUA_KEY_AQUI";
var TWITTER_CONSUMER_SECRET = "INSIRA_SUA_SECRET_AQUI";
passport.use(new TwitterStrategy({
consumerKey: TWITTER_CONSUMER_KEY,
consumerSecret: TWITTER_CONSUMER_SECRET,
callbackURL: "http://127.0.0.1:3000/auth/twitter/callback"
},
function(token, tokenSecret, profile, done) {
// NOTA: Voce tera, provavelmente, que associar o usuario do Twitter
// com um registro do usuario no banco de dados da aplicacao.
var user = profile;
return done(null, user);
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 155
}
));
Esta função fornecida para a estratégia é conhecida como “callback de verificação”. Callbacks
de verificação recebem credenciais como argumentos (neste caso o token, tokenSecret e
profile), que são usados para localizar e retornar registros do usuário. A instància user
retornada vai ser definida no request em req.user para identificar o usuário logado.
Na maioria das aplicações, você vai precisar associar a conta do Twitter com um registro do
usuário no banco de dados da aplicação. Isso permite, também, você associar outras contas
(como as do Facebook) no mesmo usuário, permitindo eles se logarem usando ambos os
serviços. Para manter este exemplo simples vai ser utilizado os dados do profile diretamente,
dispensando o uso de associações com o banco de dados.
O protocolo OAuth usado pelo Twitter envolve um processo de dois passos usando
redirecionamentos para a troca e verificação dos tokens. Isto é bastante complicado, mas o
middleware Passport faz esta tarefa fácil. Apenas adicione as seguintes rotas:
app.get('/auth/twitter', passport.authenticate('twitter'));
app.get('/auth/twitter/callback', passport.authenticate('twitter', { successReturnToOrRedirect:
'/account', failureRedirect: '/login' }));
A primeira rota vai começar a transação OAuth e redirecionar o usuário para o Twitter. Uma
vez logado, o Twitter vai redirecionar o usuário de volta para nossa aplicação e Passaport vai
trazê-lo de volta para a página original requisitada (ou /).
Fácil de mais, mas ainda há mais uma coisa a se fazer.
Configurando as sessões
A fim de manter usuário logado em nosso sistema, uma aplicação precisa implementar suporte
para sessões. Faça isso usando o cookie parser e o middleware de sessões embutidos no
Express, e inicializando o Passport.
app.use(express.static(__dirname + '/public'));
app.use(express.cookieParser());
app.use(express.session({ secret: 'usado para calcular o hash' }));
app.use(passport.initialize());
app.use(passport.session());
Quando o usuário se logar o registro do usuário é armazenado na sessão a fim de manter o
estado de logado enquanto ele nevega em seu site. Funções de serialização e deserialização
são fornecidas para controlar este processo.
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 156
passport.serializeUser(function(user, done) {
done(null, user);
});
passport.deserializeUser(function(obj, done) {
done(null, obj);
});
Como foi notado acima, se você está criando registros do usuário em seu próprio banco de
dados, você pode serializar somente o ID do usuário para minimizar a quantidade de dados
armazenados na sessão. Para manter este exemplo simples, todo o registro do usuário foi
serializado.
Rodando a aplicação
Para rodar nossa aplicação basta savá-la em um arquivo, neste exemplo chamado app.js e
executá-la passando o nome do arquivo como parâmetro para o node:
$ node app.js
Seridor Express iniciado na porta 3000
E para confirmar que tudo está funcionando você pode acessar a sua aplicação através de seu
navegador pelo endereço http://localhost:3000.
Concluindo
Se você seguiu o passo-a-passo agora os usuários podem se logar usando suas contas do
Twitter. Se você quiser se aprofundar mais nesta ferramenta consulte o guia e acesse o
repositório do github para mais detalhes de como ela funciona. Agora se você precisa
implementar uma API de autenticação, dê uma olhada nos projetos irmãos do Passport:
OAuthorize e OAuth2orize
O código completo da aplicação
Abaixo segue o código completo da aplicação, basta copiar e colar em um arquivo JavaScript,
alterar as strings INSIRA_SUA_KEY_AQUI e INSIRA_SUA_SECRET_AQUI com os dados do seu
registro no Twitter e tudo funcionará corretamente.
var express = require('express'),
passport = require('passport'),
TwitterStrategy = require('passport-twitter').Strategy,
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 157
ensureLoggedIn = require('connect-ensure-login').ensureLoggedIn,
app = express();
app.use(express.static(__dirname + '/public'));
app.use(express.cookieParser());
app.use(express.session({ secret: 'usado para calcular o hash' }));
app.use(passport.initialize());
app.use(passport.session());
passport.serializeUser(function(user, done) {
done(null, user);
});
passport.deserializeUser(function(obj, done) {
done(null, obj);
});
var TWITTER_CONSUMER_KEY = "INSIRA_SUA_KEY_AQUI";
var TWITTER_CONSUMER_SECRET = "INSIRA_SUA_SECRET_AQUI";
passport.use(new TwitterStrategy({
consumerKey: TWITTER_CONSUMER_KEY,
consumerSecret: TWITTER_CONSUMER_SECRET,
callbackURL: "http://127.0.0.1:3000/auth/twitter/callback"
},
function(token, tokenSecret, profile, done) {
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 158
// NOTA: Voce tera, provavelmente, que associar o usuario do Twitter
// com um registro do usuario no seu banco de dados.
var user = profile;
return done(null, user);
}
));
app.get('/', function(req, res){
res.send('<html><body>Ola mundo<br/><a href="/login">Login</a></body></html>');
});
app.get('/account',
ensureLoggedIn('/login'),
function(req, res) {
res.send('<html><body>Ola '+ req.user.username+'.<br/><a
href="/logout">Logout</a></body></html> ');
});
app.get('/login',
function(req, res) {
res.send('<html><body><a href="/auth/twitter">Login com Twitter</a></body></html>');
});
app.get('/logout',
function(req, res) {
req.logout();
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 159
res.redirect('/');
});
app.get('/auth/twitter', passport.authenticate('twitter'));
app.get('/auth/twitter/callback', passport.authenticate('twitter', { successReturnToOrRedirect:
'/account', failureRedirect: '/login' }));
var server = app.listen(3000);
console.log('Seridor express iniciado na porta %s', server.address().port);
JavaScript princípios básicos
A linguagem JavaScript é uma linguagem de script interpretada com base em objetos.
A linguagem JavaScript usa uma sintaxe semelhante à de C e oferece suporte a construções
estruturadas, como if...else,for e do...while. As chaves ({}) são usadas para delimitar blocos
de instrução. A linguagem oferece suporte a vários tipos de dados, entre eles String, Number,
Boolean, Object e Array. Inclui suporte para recursos avançados de data, funções
trigonométricas e expressões regulares.
JavaScript usa protótipos em vez de classes. Você pode definir um objeto criando uma função
construtora.
JavaScript é uma linguagem fracamente tipada, o que significa que você não declara os tipos
de dados das variáveis explicitamente. Em muitos casos o JavaScript executa conversões
automaticamente quando são necessárias. Por exemplo, se você adicionar um número em
um item que consiste em um texto (uma cadeia de caracteres), o número é convertido para
texto.
Escrevendo código JavaScript
Como muitas outras linguagens de programação, JavaScript é organizado em instruções,
blocos que consistem em vários conjuntos de instruções relacionadas, e comentários. Em uma
instrução você pode usar variáveis, cadeias de caracteres, números, e expressões.
Instruções
Um programa em JavaScript é um conjunto de instruções. As instruções do JavaScript
combinam expressões de forma a realizar uma tarefa por completo.
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 160
Uma declaração consiste em uma ou mais expressões, palavras-chave, ou operadores
(símbolos). Normalmente uma declaração é escrita em uma única linha, mas também pode ser
escrita em duas ou mais linhas. Além disso, duas ou mais declarações podem ser gravadas na
mesma linha separando-as com ponto-e-vírgula. Geralmente, cada nova linha inicia uma nova
declaração. É uma boa idéia finalizar explicitamente suas declarações.Você faz isso com ponto-
e-vírgula (;), que é o caractere de fim da declaração de JavaScript .
Aqui estão dois exemplos de declarações de JavaScript . Frases após os caracteres //são
comentários, partes explicativas dentro do programa.
JavaScript
var aBird = "Robin"; // Assign the text "Robin" to the variable aBird.
var today = new Date(); // Assign today's date to the variable today.
Um grupo de instruções em JavaScript circundado por chaves ({}) é chamado um bloco. As
instruções agrupadas em um bloco geralmente podem ser tratadas como uma única instrução.
Isso significa que você pode usar blocos na maioria dos locais em que o JavaScript espera uma
única instrução. Exceções notáveis incluem os cabeçalhos de repetições for e while. Observe
que as únicas declarações em um bloco terminam em ponto-e-vírgula, mas o próprio bloco
não.
Geralmente, os blocos são usados nas funções e em condições. Observe que ao contrário de
C++ e de quaisquer outras linguagens, JavaScript não considera um bloco ser um novo escopo;
somente as funções criam um novo escopo.
No exemplo a seguir, a cláusula else contém um bloco de instruções cercado por duas chaves.
O bloco é tratado como uma única instrução. Além de isso, a função própria consiste em um
bloco de instruções circundado por chaves. As instruções abaixo da função estão fora do bloco
e portanto não são parte da definição de função.
JavaScript
function inchestometers(inches)
{
if (inches < 0)
return -1;
else
{
var meters = inches / 39.37;
return meters;
}
}
var inches = 12;
var meters = inchestometers(inches);
document.write("the value in meters is " + meters);
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 161
Comentários
Um comentário de linha única de JavaScript começa com um par de barras (//). Aqui está um
exemplo de comentário em uma única linha.
JavaScript
var aGoodIdea = "Comment your code thoroughly."; // This is a single-line comment.
Um comentário de várias linhas em JavaScript começa com uma barra e um asterisco (/*), e
termina com o inverso (*/).
JavaScript
/*
This is a multiline comment that explains the preceding code statement.
The statement assigns a value to the aGoodIdea variable. The value,
which is contained between the quote marks, is called a literal. A
literal explicitly and directly contains information; it does not
refer to the information indirectly. The quote marks are not part
of the literal.
*/
Observação
Se você tentar inserir um comentário de várias linhas dentro de outro, JavaScript interpreta o
comentário de várias linhas resultante de uma maneira inesperada.* Que marca o fim do
comentário de várias linhas inserido é interpretado como o fim do comentário de várias linhas
inteira.Isso significa que o texto que segue o comentário de várias linhas inserido não será
comentado fora; em vez de isso, será interpretado como código de JavaScript , e irá gerar erros
de sintaxe.
É recomendável que você escreva todos os seus comentários como blocos de comentários de
linha única. Isso permite que você comente para fora de segmentos de código com um
comentário de várias linhas posterior.
JavaScript
// This is another multiline comment, written as a series of single-line comments.
// After the statement is executed, you can refer to the content of the
// aGoodIdea variable by using its name.
var extendedIdea = aGoodIdea + " You never know when you'll have to figure out what it
does.";
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 162
Atribuições e igualdade
O sinal de igual (=) é usado em instruções de JavaScript para atribuir valores a variáveis: é o
operador de atribuição. O operando esquerdo do operador = é sempre um Lvalue.Exemplos de
Lvalues são:
variáveis,
elementos da matriz,
propriedades do objeto.
O operador direito do operador = é sempre um Rvalue.Rvalues pode ser um valor
arbitrário de qualquer tipo, incluindo o valor de uma expressão.Aqui está um exemplo
de uma instrução de atribuição de JavaScript .
JavaScript
var anInteger = 3;
O compilador interpreta esta instrução JavaScript com o significado: “Atribua valor 3 a
anInteger variável,” ou “anInteger usa o valor 3 ".
Esteja certo que entende a diferença entre operador de atribuição (=) e == o operador
de igualdade ().Quando você deseja comparar dois valores para descobrir se forem
iguais, use dois sinais de igual (==).Isso é abordado em detalhes em Fluxo de programa
de controle.
Expressões
Um valor da expressão de JavaScript pode ser de qualquer tipo válido de JavaScript -
um número, uma cadeia de caracteres, um objeto, e assim por diante. As expressões
mais simples são as literais. Aqui estão alguns exemplos de expressões literais
JavaScript.
JavaScript
3.9 // numeric literal
"Hello!" // string literal
false // boolean literal
null // literal null value
{x:1, y:2} // Object literal
[1,2,3] // Array literal
function(x){return x*x;} // function literal
Expressões mais complicadas podem conter variáveis, chamadas de função, e outras
expressões. Você pode combinar expressões para criar expressões complexas usando
operadores.Exemplos de operadores são: + () - (adição, subtração, multiplicação) * (), e
/ (divisão).
Aqui estão alguns exemplos de expressões complexas JavaScript .
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 163
JavaScript
var anExpression = 3 * (4 / 5) + 6;
var aSecondExpression = Math.PI * radius * radius;
var aThirdExpression = aSecondExpression + "%" + anExpression;var aFourthExpression = "(" + aSecondExpression + ") % (" + anExpression + ")";
Variáveis (JavaScript)
Em JavaScript, uma variável contém um valor, como "hello" ou 5.Quando você usa a variável,
faz referência aos dados que ela representa, por exemplo NumberOfDaysLeft = EndDate –
TodaysDate.
Você usa variáveis para armazenar, recuperar e manipular valores que aparecem no seu
código.Tente dar nomes significativos às variáveis, para que as outras pessoas possam
compreender melhor a finalidade do seu código.
A primeira vez que uma variável aparece no script é a sua declaração.A primeira menção da
variável a configura na memória, para que mais tarde você possa fazer referência a ela no seu
script.Você deve declarar variáveis antes de usá-las.Para fazer isso, use a palavra-chave var.
JavaScript
// A single declaration.
var count;
// Multiple declarations with a single var keyword.
var count, amount, level;
// Variable declaration and initialization in one statement.
var count = 0, amount = 100;
Se você não inicializar sua variável na instrução var, ela usará automaticamente o valor
undefined.
Nomeando variáveis
A linguagem JavaScript faz distinção entre maiúsculas e minúsculas.Isso significa que um nome
de variável, como myCounter, é diferente do nome de variável MYCounter.Nomes de variáveis
podem ser de qualquer comprimento.As regras para a criação de nomes de variável legais são
as seguintes:
O primeiro caractere deve ser uma letra ASCII (em maiúscula ou minúscula) ou um
caractere de sublinhado (_).Observe que um número não pode ser usado como o
primeiro caractere.
Os caracteres subsequentes devem ser letras, números ou sublinhados (_).
O nome da variável não deve ser uma palavra reservada.
Veja a seguir alguns exemplos de nomes de variável válidos:
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 164
_pagecount
Part9
Number_Items
Veja a seguir alguns exemplos de nomes de variável inválidos:
JavaScript
// Cannot begin with a number.
99Balloons
// The ampersand (&) character is not a valid character for variable names.
Alpha&Beta
Quando quiser declarar uma variável e inicializá-la, mas não quiser dar a ela um valor
específico, atribua o valor null.Veja um exemplo.
JavaScript
var bestAge = null;
var muchTooOld = 3 * bestAge; // muchTooOld has the value 0.
Se você declarar uma variável sem lhe atribuir um valor, ela terá o valor undefined.Veja um
exemplo.
JavaScript
var currentCount;
// finalCount has the value NaN because currentCount is undefined.
var finalCount = 1 * currentCount;
O valor null se comporta como o número 0, enquanto undefined se comporta como o valor
especial NaN (não é um número).Se você comparar um valor null e um valor undefined, verá
que eles são iguais.
É possível declarar uma variável sem usar a palavra-chave var na declaração e atribuir um valor
para ela.Trata-se de uma declaração implícita.
JavaScript
// The variable noStringAtAll is declared implicitly.
noStringAtAll = "";
Não é possível usar uma variável que nunca tenha sido declarada.
JavaScript
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 165
// Error. Length and width do not yet exist.
var area = length * width;
Coerção
A linguagem JavaScript é uma linguagem fracamente tipada, ao contrário de linguagens
fortemente tipadas como C++. Isso significa que variáveis JavaScript não têm nenhum tipo
predeterminado. Em vez de isso, o tipo de uma variável é o tipo do seu valor.Esse
comportamento permite que você trate um valor como se ele fosse de um tipo diferente.
Em JavaScript, você pode realizar operações em valores de diferentes tipos sem causar uma
exceção. O interpretador JavaScript converte implicitamente, ou força, um dos tipos de dados
no outro e, em seguida, realiza a operação. As regras para coerção de valores Booleanos, de
cadeia de caracteres e de número são as seguintes:
Se você adicionar um número e uma cadeia de caracteres, o número será forçado para
uma cadeia de caracteres.
Se você adicionar um Booleano e uma cadeia de caracteres, o Booleano será forçado
para uma cadeia de caracteres.
Se você adicionar um número e um Booleano, o Booleano será forçado para um
número.
No exemplo a seguir, um número adicionado a uma cadeia de caracteres resulta em uma
cadeia de caracteres.
JavaScript
var x = 2000;
var y = "Hello";
// The number is coerced to a string.
x = x + y;
document.write(x);
// Output:
// 2000Hello
Cadeias de caracteres são convertidas automaticamente em números equivalentes para fins
de comparação.Para converter explicitamente uma cadeia de caracteres em um número
inteiro, use a função parseInt.Para converter explicitamente uma cadeia de caracteres em um
número, use a função parseFloat.
Tipos de dados (JavaScript)
No JavaScript, existem três tipos de dados primários, dois tipos de dados compostos e dois
tipos de dados especiais.
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 166
Tipos de Dados Primários
Os tipos de dados primários (primitivos) são:
Cadeia de caracteres
Número
Booleano
Tipos de dados compostos
Os tipos de dados compostos (de referência) são:
Object
Matriz
Tipos de Dados Especiais
Os tipos de dados especiais são:
Nulo
Indefinido
Tipo de dados de cadeia de caracteres
Um valor de cadeia de caracteres é uma cadeia de zero ou mais caracteres Unicode (letras,
dígitos e sinais de pontuação).Tipos de dados de cadeia de caracteres são usados para
representar texto em JavaScript.Você inclui literais de cadeia de caracteres em seus scripts ao
delimitá-los por aspas simples ou duplas.Aspas duplas podem estar contidas em cadeias de
caracteres delimitadas por aspas simples, enquanto aspas simples podem estar contidas em
cadeias de caracteres delimitadas por aspas duplas.Veja a seguir alguns exemplos de cadeias
de caracteres:
JavaScript
"Happy am I; from care I'm free!"
'"Avast, ye lubbers!" roared the technician.'
"45"
'c'
Observe que JavaScript não tem um tipo para representar um único caractere.Para
representar um único caractere em JavaScript, você cria uma cadeia de caracteres que consiste
em apenas um caractere.Uma cadeia de caracteres que contém zero caracteres ("") é uma
cadeia de caracteres vazia (de comprimento zero).
O JavaScript fornece sequências de escape que você pode incluir em cadeias de caracteres
para criar os caracteres que não podem ser digitados diretamente.Por exemplo, \t especifica
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 167
um caractere de tabulação.Para obter mais informações, consulte Caracteres especiais
(JavaScript).
Tipo de Dados de Número
Em JavaScript, não há diferença entre valores de número inteiro e de ponto flutuante; um
número JavaScript pode ser qualquer um dos dois (internamente, JavaScript representa todos
os números como valores de ponto flutuante).
Valores Inteiros
Valores inteiros podem ser números inteiros positivos, números inteiros negativos e 0.Eles
podem ser representados na base 10 (decimal), na base 16 (hexadecimal) e na base 8 (octal).A
maioria dos números em JavaScript é escrita em decimal.
Você indica números inteiros hexadecimais ("hex") prefixando-os com um "0x" à esquerda
(zero e x|X).Eles podem conter somente dígitosde 0 a 9 e letras de A a F (maiúsculas ou
minúsculas).As letras de A a F são usadas para representar, como dígitos únicos, o intervalo de
10 a 15 na base 10.Ou seja, 0xF é equivalente a 15 e 0x10, a 16.
Você indica inteiros octais prefixando-os com um "0" (zero) à esquerda.Eles podem conter
somente dígitos de 0 a 7.Um número com "0" à esquerda e os dígitos "8" e/ou "9" é
interpretado como um número decimal.
Números hexadecimais e octais podem ser negativos, mas não podem ter uma parte decimal e
não podem ser escritos em notação científica (exponencial).
Observação
A partir do Modo padrão do Internet Explorer 9, modo padrão do Internet Explorer 10, modo
padrão do Explorer 11 e aplicativos da Windows Store, a função parseInt não trata uma cadeia
de caracteres que possui um prefixo "0" como um octal.No entanto, quando você não estiver
usando a função parseInt, cadeias de caracteres com um prefixo "0" ainda poderão ser
interpretadas como octais.
Valores de Ponto Flutuante
Valores de ponto flutuante podem ser números inteiros com uma parte decimal.Além de isso,
eles podem ser expressos em notação científica.Ou seja, um "e" em maiúscula ou minúscula é
usado para representar "dez à potência de".JavaScript representa números usando o padrão
de ponto flutuante IEEE 754 de oito bytes para representação numérica.Isso significa que você
pode escrever números de no máximo 1,79769x10308 e de no mínimo 5x10-324.Um número
que contém um ponto decimal e um único "0" antes desse ponto decimal é interpretado como
um número de ponto flutuante decimal.
Observe que um número que começa com "0x" ou "00" e contém um ponto decimal irá gerar
um erro.Veja a seguir alguns exemplos de números JavaScript.
Número Descrição
Equivalente
decimal
.0001, 0.0001,
1e-4, 1.0e-4
Quatro números de ponto flutuante equivalentes. 0.0001
3.45e2 Um número de ponto flutuante. 345
45 Um inteiro. 45
0378 Um inteiro.Embora se pareça com um número octal (começa 378
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 168
com zero), 8 não é um dígito octal válido e, portanto, o
número é tratado como um decimal.
0377
Um inteiro octal.Observe que, embora ele pareça ser apenas
uma unidade menor que o número acima, seu valor real é
bem diferente.
255
0.0001
Um número de ponto flutuante.Mesmo começando com zero,
este não é um número octal, pois possui um ponto decimal.
0.0001
00.0001
É um erro.Os dois zeros à esquerda marcam o número como
um octal, mas octals não permitem um componente decimal.
N/D (erro do
compilador)
0Xff Um inteiro hexadecimal. 255
0x37CF Um inteiro hexadecimal. 14287
0x3e7
Um inteiro hexadecimal.Observe que o 'e' não é tratado como
exponenciação.
999
0x3.45e2
É um erro.Números hexadecimais não podem ter partes
decimais.
N/D (erro do
compilador)
Além disso, o JavaScript contém números com valores especiais.Eles são:
NaN (não é um número).Usado quando uma operação matemática é realizada em
dados inadequados, como cadeias de caracteres ou o valor undefined
Infinito positivo.Usado quando um número positivo é muito grande para ser
representado em JavaScript
Infinito negativo.Usado quando um número negativo é muito grande para ser
representado em JavaScript
0 positivo e negativo.JavaScript faz distinção entre zeros positivos e negativos.
Tipo de dados Booliano
Enquanto os tipos de dados cadeia de caracteres e número podem ter um número
praticamente ilimitado de valores diferentes, o tipo de dados booliano só pode ter dois.Eles
são os literais true e false.Um valor booliano é um valor verdadeiro: especifica se a condição é
verdadeira ou não.
As comparações que você faz nos seus scripts sempre têm um resultado Booliano.Considere a
seguinte linha de código JavaScript.
JavaScript
y = (x == 2000);
Aqui, o valor da variável x é comparado ao número 2000.Se for, o resultado da comparação
será o valor booliano true, que é atribuído à variável y.Se x não for igual a 2000, o resultado da
comparação será o valor booliano false.
Valores boolianos são especialmente úteis em estruturas de controle.O código a seguir
combina uma comparação que cria um valor booliano diretamente com uma instrução que usa
esse valor.Considere a seguinte amostra de código JavaScript.
JavaScript
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 169
if (x == 2000) {
z = z + 1;
}
else {
x = x + 1;
}
A instrução if/else no JavaScript executará uma ação se um valor booliano for true (z = z + 1), e
uma ação alternativa se o valor booliano for false (x = x + 1).
Você pode usar qualquer expressão como uma expressão comparativa.Qualquer expressão
avaliada como 0, nula, indefinida ou uma cadeia de caracteres vazia é interpretada como
false.Uma expressão que é avaliada como qualquer outro valor é interpretada como true.Por
exemplo, você pode usar uma expressão como:
JavaScript
// This may not do what you expect. See below!
if (x = y + z)
Observe que a linha anterior não verifica se x é igual a y + z, pois apenas um sinal de igual (o
operador de atribuição) é usado.Em vez disso, o código anterior atribui o valor y + z à variável x
e depois verifica se o resultado da expressão inteira (o valor de x) é zero.Para verificar se x é
igual a y + z, você precisará usar o código a seguir.
JavaScript
// This is different from the code above!
if (x == y + z)
Para obter mais informações sobre comparações, consulte Controlando o fluxo de programas.
O Tipo de Dados nulo
O tipo de dados null tem apenas um valor em JavaScript: null.A palavra-chave null não pode
ser usada como o nome de uma função ou variável.
Uma variável que contém null não contém nenhum Número, Cadeia de Caracteres, Booliano,
Matriz ou Objeto.Você pode apagar o conteúdo de uma variável (sem a excluir) atribuindo o
valor null.
Observe que, em JavaScript, null não é o mesmo que 0 (como no caso de C e C++).Observe
também que o operador typeof em relatórios do JavaScript relatará valores null como sendo
do tipo Object, e não do tipo null.Esse comportamento potencialmente confuso serve para
compatibilidade com versões anteriores.
O Tipo de Dados indefinido
O valor undefined é retornado quando você usa uma propriedade do objeto que não existe,
ou uma variável que tenha sido declarada, mas que nunca tenha tido um valor atribuído a ela.
você pode verificar se uma variável existe comparando-a a undefined, embora seja possível
verificar se o tipo é undefined comparando o tipo de variável à cadeia de caracteres
"indefinida".O exemplo a seguir mostra como descobrir se a variável x foi declarada:
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 170
JavaScript
var x;
// This method works.
if (x == undefined) {
document.write("comparing x to undefined <br/>");
}
.
// This method doesn't work - you must check for the string "undefined".
if (typeof(x) == undefined) {
document.write("comparing the type of x to undefined <br/>");
}
// This method does work.
if (typeof(x) == "undefined") {
document.write("comparing the type of x to the string 'undefined'");
}
// Output:
// comparing x to undefined
// comparing the type of x to the string 'undefined'
Você também pode comparar o valor indefinido a null.Esta comparação será true se a
propriedade for someObject.propnull ou se a propriedade someObject.prop não existir.
JavaScript
someObject.prop == null;
Para descobrir se uma propriedadede objeto existe, você pode usar o operador in:
JavaScript
if ("prop" in someObject)
// someObject has the property 'prop'
Operadores (JavaScript)
O JavaScript tem uma gama completa dos operadores, incluindo operadores aritméticos,
lógicos, bit a bit, de atribuição e também alguns operadores diversificados.Para explicações e
exemplos, consulte os tópicos sobre operadores específicos.
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 171
Operadores computacionais
Descrição Símbolo
Negação unária -
Incremento ++
Redução --
Multiplicação *
Divisão /
Módulo aritmético %
Adição +
Subtração -
Operadores lógicos
Descrição Símbolo
NÃO lógico !
Menor que <
Maior que >
Menor ou igual a <=
Maior ou igual a >=
Igualdade ==
Desigualdade !=
E lógico &&
OU lógico ||
Condicional (ternário) ?:
Vírgula ,
Igualdade estrita ===
Desigualdade estrita !==
Operadores bit a bit
Descrição Símbolo
NOT bit a bit ~
Deslocamento para a esquerda bit a bit <<
Deslocamento para a direita bit a bit >>
Deslocamento para a direita sem sinal >>>
AND bit a bit &
XOR bit a bit ^
OR bit a bit |
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 172
Operadores de Atribuição
Descrição Símbolo
Atribuição =
Atribuição composta OP= (como += e &=)
Operadores diversos
Descrição Símbolo
excluir excluir
typeof typeof
void void
instanceof instanceof
novo novo
em em
Igualdade e igualdade estrita
A diferença entre o == (igualdade) e === (igualdade estrita) é que o operador de igualdade
forçará valores de diferentes tipos antes de verificar a igualdade.Por exemplo, comparar a
cadeia de caracteres "1" com o número 1 fará uma comparação como true.O operador de
igualdade estrita, por outro lado, não forçará valores para diferentes tipos e, portanto, a
cadeia de caracteres "1" não será comparada como igual ao número 1.
Cadeias de caracteres primitivas, números e boolianos são comparados por valor.Se eles
tiverem o mesmo valor, serão iguais.Objetos (incluindo Array, Function, String, Número,
Boolean, Erro, Date e objetos RegExp) são comparados por referência.Mesmo que duas
variáveis desses tipos tenham o mesmo valor, elas só serão iguais se fizerem referência
exatamente ao mesmo objeto.
Por exemplo:
JavaScript
// Two strings with the same value.
var string1 = "Hello";
var string2 = "Hello";
// Two String objects with the same value.
var StringObject1 = new String(string1);
var StringObject2 = new String(string2);
if (string1 == string2)
document.write("string1 is equal to string2 <br/>");
if (StringObject1 != StringObject2)
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 173
document.write("StringObject1 is not equal to StringObject2 <br/>");
// To compare the values of String objects, use the toString() or valueOf() methods.
if (StringObject1.valueOf() == StringObject2.valueOf())
document.write("The value of StringObject1 is equal to the value of StringObject2");
//Output:
// string1 is equal to string2
// StringObject1 is not equal to StringObject2
// The value of StringObject1 is equal to the value of StringObject2
Precedência do operador (JavaScript)
A precedência dos operadores descreve a ordem em que as operações são realizadas quando
uma expressão é avaliada.As operações com uma precedência maior são realizadas antes
daquelas com precedência menor.Por exemplo, a multiplicação é realizada antes da adição.
JavaScript Operadores
A tabela a seguir lista os operadores JavaScript ordenados da maior para a menor
precedência.Operadores com a mesma precedência são avaliados da esquerda para a direita.
Operador Descrição
. [ ] ( )
Acesso a campos, indexação de matrizes, chamadas de funções e
agrupamento de expressões
++ -- - ~ ! delete new
typeof void
Operadores unários, tipo de dados de retorno, criação de objetos,
valores indefinidos
* / % Multiplicação, divisão, divisão de módulo
+ - + Adição, subtração, concatenação de cadeias de caracteres
<< >> >>> Deslocamento de bits
< <= > >= instanceof
Menor que, menor que ou igual a, maior que, maior que ou igual a,
instância de
== != === !== Igualdade, desigualdade, igualdade estrita e desigualdade estrita
& AND bit a bit
^ XOR bit a bit
| OR bit a bit
&& AND lógico
|| OR lógico
?: Condicional
= OP= Atribuição, atribuição com operação (como += e &=)
, Avaliação múltipla
Os parênteses são usados para alterar a ordem de avaliação determinada pela precedência dos
operadores.Isso significa que uma expressão entre parênteses é totalmente avaliada antes que
o seu valor seja usado no restante da expressão.
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 174
Por exemplo:
JavaScript
var result = 78 * 96 + 3;
document.write(result);
document.write("<br/>");
result = 78 * (9 + 3);
document.write(result);
// Output:
// 7491
// 936
Há três operadores na primeira expressão: =, * e +.De acordo com as regras de precedência de
operadores, eles são avaliados na seguinte ordem: *, +, = (78 * 96 = 7488, 7488 + 3 = 7491).
Na segunda expressão, o operador ( ) é avaliado primeiro, de modo que a expressão de adição
é avaliada antes da multiplicação (9 + 3 = 12, 12 * 78 = 936).
O exemplo a seguir mostra uma instrução que inclui uma variedade de operadores e é
resolvida como true.
JavaScript
var num = 10;
if(5 == num / 2 && (2 + 2 * num).toString() === "22") {
document.write(true);
}
// Output:
// true
Os operadores são avaliados nesta ordem: () para o agrupamento, *, + (dentro de
agrupamento), "." para a função, () para a função, /, ==, ===, e &&.
Controlando o fluxo de programas (JavaScript)
Normalmente, instruções em um script JavaScript são executadas uma após a outra, na ordem
em que são escritas.Isso é chamado de execução sequencial e é a direção padrão do fluxo do
programa.
Uma alternativa para a execução sequencial transfere o fluxo do programa para outra parte do
script.Ou seja, em vez de executar a próxima instrução na sequência, outra instrução é
executada.
Para tornar um script útil, essa transferência de controle deve ser feita de maneira lógica.A
transferência do controle do programa se baseia em uma decisão, que é o resultado de qual
instrução é verdadeira (retornar um booliano true ou false).Você cria uma expressão e, depois,
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 175
testa se o seu resultado é verdadeiro.Há dois tipos principais de estruturas de programa que
fazem isso.
O primeiro é a estrutura de seleção.Você usa para especificar rotas alternativas do fluxo do
programa, criando uma junção no seu programa (como uma bifurcação em uma estrada).Há
quatro estruturas de seleção disponíveis em JavaScript.
a estrutura de seleção única (if),
a estrutura de seleção dupla (if/else),
o operador ternário embutido ?:
estrutura de seleção múltipla (switch).
O segundo tipo de estrutura de controle de programa é a estrutura de repetição.Você usa para
especificar que uma ação deve ser repetida enquanto uma certa condição permanecerverdadeira.Quando as condições da instrução de controle tiverem sido atendidas (em geral
depois de um número específico de iterações), o controle será transferido para a instrução
seguinte além da estrutura de repetição.Há quatro estruturas de repetição disponíveis em
JavaScript.
a expressão é testada no topo do loop (while),
a expressão é testada no final do loop (do/while),
operam em cada uma das propriedades de um objeto (for/in).
repetição controlada por contador (para).
Você pode criar scripts bastante complexos aninhando e empilhando estruturas de controle de
seleção e repetição.
Um terceiro formato de fluxo de programa estruturado é fornecido pela manipulação de
exceções, que não é discutida neste documento.
Usando instruções condicionais
JavaScript oferece suporte para instruções condicionais if e if...else.Em instruções if, uma
condição é testada e, se ela corresponder ao teste, o código JavaScript relevante será
executado.Na instrução if...else, o código diferente será executado se a condição for
reprovada no teste.A forma mais simples de uma instrução if pode ser escrita em uma linha,
mas instruções if e if...else de várias linhas são muito mais comuns.
Os exemplos a seguir demonstram sintaxes que você pode usar com instruções if e if...else.O
primeiro exemplo mostra o tipo mais simples de teste booleano.Se (e somente se) o item
entre parênteses for avaliado como (ou puder ser forçado como) verdadeiro, a instrução ou o
bloco de instruções depois de se será executado.
JavaScript
function GetReaction(newShip, color, texture, dayOfWeek)
{
// The test succeeds if the newShip Boolean value is true.
if (newShip)
{
return "Champagne Bottle";
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 176
}
// The test succeeds if both conditions are true.
if (color == "deep yellow" && texture == "large and small wrinkles")
{
return "Is it a crenshaw melon?";
}
// The test succeeds if either condition is true.
if ((dayOfWeek == "Saturday") || (dayOfWeek == "Sunday"))
{
return "I'm off to the beach!";
}
else
{
return "I'm going to work.";
}
}
var reaction = GetReaction(false, "deep yellow", "smooth", "Sunday");
document.write(reaction);
// Output: I'm off to the beach!
Operador condicional
JavaScript também oferece suporte para um formato condicional implícito.Esse formato usa
um ponto de interrogação após a condição a ser testada (em vez da palavra if antes da
condição).Ele também especifica duas alternativas: uma a ser usada se a condição for atendida
e outra se a condição não for atendida.Essas alternativas devem ser separadas por dois
pontos.
JavaScript
var AMorPM = (theHour >= 12) ? "PM" : "AM";
Se você tiver várias condições a serem testadas e souber que uma delas tem mais chances de
ser aprovada ou reprovada do que as outras, será possível usar um recurso chamado de
"avaliação em curto circuito" para acelerar a execução do seu script.Quando a linguagem
JavaScript avalia uma expressão lógica, ela somente avalia as subexpressões necessárias para
se chegar a um resultado.
Por exemplo, se você tiver uma expressão E como ((x == 123) && (y == 6)), JavaScript verificará
primeiro se x é 123.Se não for, a expressão inteira não poderá ser verdadeira, mesmo que y
seja igual a 6.Portanto, o teste para y nunca é feito e JavaScript retorna o valor falso.
De maneira semelhante, se apenas uma de várias condições tiver que ser verdadeira (usando
o operador ||), o teste será interrompido assim que qualquer uma dessas condições for
aprovada no teste.Isso é eficaz quando as condições a serem testadas envolvem a execução de
chamadas de função ou outras expressões complexas.Com isso em mente, quando você
escrever expressões OR, insira primeiro as condições com maiores chances de serem
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 177
verdadeiras.Quando escrever expressões AND, insira primeiro as condições com maiores
chances de serem falsas .
Uma vantagem de projetar o seu script dessa maneira é que runsecond() não será executado
no exemplo a seguir se runfirst() retornar 0.
JavaScript
if ((runfirst() == 0) || (runsecond() == 0)) {
// some code
}
Usando Loops
Há várias maneiras de executar repetidamente uma instrução ou um bloco de instruções.No
geral, a execução repetitiva é chamada de loop ou iteração.Uma iteração é simplesmente uma
única execução de um loop.Em geral, ele é controlado por um teste de uma variável cujo valor
é alterado sempre que o loop é executado.JavaScript oferece suporte para quatro tipos de
loops: loops for, loops for...in, loops while e loops do...while.
Usando para Loops
A instrução for especifica uma variável de contador, uma condição de teste e uma ação que
atualiza o contador.Antes de cada iteração do loop, a condição é testada.Se o teste for bem-
sucedido, o código dentro do loop será executado.Se o teste for malsucedido, o código dentro
do loop não será executado, e o programa continuará na primeira linha de código
imediatamente após o loop.Depois que o loop é executado, a variável de contador é atualizada
antes do início da próxima iteração.
Se a condição de loop nunca for atendida, o loop nunca será executado.Se a condição de teste
sempre for atendida, um loop infinito será gerado.Embora o primeiro possa ser desejável em
certos casos, o último raramente é. Portanto, tenha cautela ao escrever suas condições de
loop.
JavaScript
// The update expression ("icount++" in the following examples)
// is executed at the end of the loop, after the block of
// statements that forms the body of the loop is executed, and
// before the condition is tested.
// Set a limit of 10 on the loop.
var howFar = 10;
// Create an array called sum with 10 members, 0 through 9.
var sum = new Array(howFar);
sum[0] = 0;
// Iterate from 0 through 9.
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 178
var theSum = 0;
for(var icount = 0; icount < howFar; icount++)
{
theSum += icount;
sum[icount] = theSum;
}
// This code is not executed at all, because icount is not greater than howFar.
var newSum = 0;
for(var icount = 0; icount > howFar; icount++)
{
newSum += icount;
}
// This is an infinite loop.
var sum = 0;
for(var icount = 0; icount >= 0; icount++)
{
sum += icount;
}
Usando loops for...in
JavaScript fornece um tipo especial do loop para percorrer todas as propriedades definidas
pelo usuário de um objeto ou todos os elementos de uma matriz.O contador de loop em um
loop for...in é uma cadeia de caracteres, e não um número.Ele contém o nome da propriedade
atual ou o índice do elemento de matriz atual.
JavaScript
// Create an object with some properties
var myObject = new Object();
myObject.name = "James";
myObject.age = "22";
myObject.phone = "555 1234";
// Enumerate (loop through)_all the properties in the object
for (var prop in myObject)
{
// This displays "The property 'name' is James", etc.
document.write("The property '" + prop + "' is " + myObject[prop]);
// New line.
document.write("<br />");
}
Embora loops for...in pareçam semelhantes a loops For Each...Next VBScript, eles não
funcionam da mesma maneira.O JavaScript for...in loop é iterado por propriedades de objetos
JavaScript.O loop For Each...Next VBScript é iterado por itens de uma coleção.Para executar
um loop nas coleções no JavaScript,você precisará usar o objeto de Objeto Enumerator
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 179
(JavaScript), ou se presente, o método forEach do objeto de coleção.Embora alguns objetos,
como aqueles no Internet Explorer, ofereçam suporte para ambos os loops For Each...Next
VBScript e o JavaScript for...in , a maioria dos objetos não tem esse suporte.
Usando loops while
Um loop while é semelhante a um loop for. A diferença é que um loop while não tem uma
expressão de atualização ou uma variável de contador interno.Se você quiser controlar a
execução repetitiva de uma instrução ou de um bloco de instruções, mas precisar de uma
regra mais complexa do que simplesmente "executar este código n vezes", use um loop
while.O exemplo a seguir usa o modelo de objeto do Internet Explorer e um loop while para
fazer ao usuário uma pergunta simples.
JavaScript
var x = 0;
while ((x != 5) && (x != null))
{
x = window.prompt("What is my favorite number?", x);
}
if (x == null)
window.alert("You gave up!");
else
window.alert("Correct answer!");
Observação
Como os loops while não têm variáveis explícitas de contador interno, eles são mais
vulneráveis a loops infinitos do que os outros tipos de loops.Além disso, como não é
necessariamente fácil descobrir onde ou quando a condição do loop é atualizada, é fácil
escrever um loop while no qual a condição nunca é atualizada.Por esse motivo, você deve ter
cautela ao projetar loops while.
Conforme mencionado acima, há também um loop do...while em JavaScript que é semelhante
ao loop while, com a diferença de que ele sempre é executado pelo menos uma vez, pois a
condição é testada no final do loop, e não no início.Por exemplo, o loop acima pode ser
novamente escrito como:
JavaScript
var x = 0;
do
{
x = window.prompt("What is my favorite number?", x);
} while ((x != 5) && (x != null));
if (x == null)
window.alert("You gave up!");
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 180
else
window.alert("Correct answer!");
Usando instruções break e continue
Em JavaScript, a instrução break é usada para interromper a execução de um loop se uma
certa condição for atendida. (Observe que break também é usada para sair de um bloco
switch).A instrução continue pode ser usada para saltar imediatamente para a próxima
iteração, ignorando o restante do bloco de código, atualizando ao mesmo tempo a variável de
contador se o loop for do tipo for ou for...in.
O exemplo a seguir se baseia no exemplo anterior para usar instruções break e continue para
controlar o loop.
JavaScript
var x = 0;
do
{
x = window.prompt("What is my favorite number?", x);
// Did the user cancel? If so, break out of the loop
if (x == null)
break;
// Did they enter a number?
// If so, no need to ask them to enter a number.
if (Number(x) == x)
continue;
// Ask user to only enter in numbers
window.alert("Please only enter in numbers!");
} while (x != 5)
if (x != 5)
window.alert("You gave up!");
else
window.alert("Correct answer!");
Funções (JavaScript)
As funções JavaScript executam ações. Elas também podem retornar valores.Às vezes, eles são
resultados de cálculos ou comparações.Funções também são chamadas de "métodos globais".
Elas combinam diversas operações em um nome.Isso permite simplificar seu código.Você pode
escrever um conjunto de instruções, nomeá-lo e executar todo o conjunto chamando-o e
transmitindo a ele todas as informações necessárias.
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 181
Você transmite informações a uma função colocando as informações entre parênteses após o
nome da função.Trechos de informações que são transmitidos a uma função são chamados de
argumentos ou parâmetros.Algumas funções não usam nenhum argumento, enquanto outras
usam um ou mais argumentos.Em algumas funções, o número de argumentos depende de
como você está usando a função.
O JavaScript dá suporte a dois tipos de funções: aquelas que são internas à linguagem e as que
são criadas por você.
Funções internas
A linguagem JavaScript inclui várias funções internas.Algumas delas permitem que você
processe expressões e caracteres especiais, enquanto outras convertem cadeias de caracteres
em valores numéricos.
Consulte Métodos (JavaScript) para obter informações sobre essas funções internas.
Criando suas próprias funções
Você pode criar suas próprias funções e usá-las quando for necessário.Uma definição de
função consiste em uma instrução de função e um bloco de instruções JavaScript.
A função checkTriplet no exemplo a seguir usa os comprimentos dos lados de um triângulo
como argumentos.Ela calcula por meio deles se o triângulo é um triângulo retângulo
verificando se os três números constituem um trio de Pitágoras (o quadrado do comprimento
da hipotenusa de um triângulo retângulo é igual à soma dos quadrados dos comprimentos dos
outros dois lados).A função checkTriplet chama uma das duas outras funções para fazer o
teste.
Observe o uso de um número muito pequeno ("épsilon") como variável de teste na versão de
ponto flutuante do teste.Devido a incertezas e erros de arredondamento em cálculos de ponto
flutuante, não é prático testar diretamente se os três números constituem um trio de
Pitágoras, a menos que se saiba que os três valores em questão são inteiros.Como um teste
direto é mais preciso, o código neste exemplo determina se ele é apropriado e, se for, o utiliza.
JavaScript
var epsilon = 0.00000000001; // Some very small number to test against.
// The test function for integers.
function integerCheck(a, b, c)
{
// The test itself.
if ( (a*a) == ((b*b) + (c*c)) )
return true;
return false;
} // End of the integer checking function.
// The test function for floating-point numbers.
function floatCheck(a, b, c)
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 182
{
// Make the test number.
var delta = ((a*a) - ((b*b) + (c*c)))
// The test requires the absolute value
delta = Math.abs(delta);
// If the difference is less than epsilon, then it's pretty close.
if (delta < epsilon)
return true;
return false;
} // End of the floating-poing check function.
// The triplet checker.
function checkTriplet(a, b, c)
{
// Create a temporary variable for swapping values
var d = 0;
// First, move the longest side to position "a".
// Swap a and b if necessary
if (b > a)
{
d = a;
a = b;
b = d;
}
// Swap a and c if necessary
if (c > a)
{
d = a;
a = c;
c = d;
}
// Test all 3 values. Are they integers?
if (((a % 1) == 0) && ((b % 1) == 0) && ((c % 1) == 0))
{
// If so, use the precise check.
return integerCheck(a, b, c);
}
else
{
// If not, get as close as is reasonably possible.
return floatCheck(a, b, c);
}
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 183
} // End of the triplet check function.
// The next three statements assign sample values for testing purposes.
var sideA = 5;
var sideB = 5;
var sideC = Math.sqrt(50.001);
//Call the function. After the call, 'result' contains the result.
var result = checkTriplet(sideA, sideB, sideC);
Funções de seta
A sintaxe de função de seta, =>, fornece um método abreviado de especificar uma função
anônima.Esta é a sintaxe de função de seta.
JavaScript
([arg] [, arg]) => {
statements
}
Os valores à esquerda da seta, que podem ser delimitados por parênteses, especificam os
argumentos transmitidos para a função.Um único argumento para a função não requer
parênteses.Se nenhum argumento for passado, são necessários parênteses.A definição da
função à direita da seta pode ser uma expressão, como v + 1, ou um bloco de instruções entre
chaves ({}).
Importante
A sintaxe de função de seta tem suporte apenas no Microsoft Edge.
Não é possível usar o operador new com uma função de seta.
Os exemplos de código a seguir mostram o uso da função de seta com expressões como as
definições de função.No primeiro exemplo, v é transmitido como o argumento para a
expressão.No segundo exemplo, v e i são transmitidos como argumentos para a expressão.
var evens = [2, 4, 6, 8];
// Using standard syntax.
var odds = evens.map(function(v) { return v + 1; });
// Using arrow function syntax.
// Add one to each value to produce output.
var odds = evens.map(v => v + 1);
// The following line of code adds the index value to the passed
// in value to produce output.
// Note: the second argument to the callback function in the map
// method is the index value (i).
var nums = evens.map((v, i) => v + i);
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 184
console.log(odds);
console.log(nums);
// Output:
// [object Array] [3, 5, 7, 9]
// [object Array] [2, 5, 8, 11]
O exemplo de código mostra o uso da função de seta com um bloco de instruções.
JavaScript
var fives = new Array();
// Statement block, re-using nums array from previous example.
// Note: The first argument to the callback function in forEach
// is the value of the array element (v).
nums.forEach(v => {
if (v % 5 === 0)
fives.push(v);
});
console.log(fives);
// Output:
// [object Array] [5]
Diferente das funções padrão, as funções de Seta compartilham o mesmo objeto lexical this
que o código ao redor, o que pode ser usado para eliminar a necessidade de soluções
alternativas, como var self = this;.
O exemplo a seguir mostra que o valor do objeto this dentro da função de seta é o mesmo que
o código ao redor (ainda se refere à variável bob variável).
JavaScript
var bob = {
_name: "Bob",
_friends: ["Pete", "Joe", "Larry"],
printFriends() {
this._friends.forEach(f =>
console.log(this._name + " knows " + f));
}
}
// Output:
// Bob knows Pete
// Bob knows Joe
// Bob knows Larry
As funções de seta também compartilham o mesmo objeto lexical arguments que o código ao
redor (como o objeto this).
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 185
Parâmetros padrão
Você pode especificar um valor padrão para um parâmetro em uma função atribuindo a ele
um valor inicial.O valor padrão pode ser um valor constante ou uma expressão.
Importante
Parâmetros padrão têm suporte apenas no Microsoft Edge com recursos JavaScript
experimentais habilitados (about:flags).
No exemplo a seguir, o valor padrão de y é 10 e o valor padrão de z é 20.A função usará 10
como valor de y, a menos que o chamador transmita um valor distinto (ou indefinido) como
segundo argumento.A função usará 20 como valor de z, a menos que o chamador transmita
um valor distinto (ou indefinido) como terceiro argumento.
JavaScript
var val = 20;
function f(x, y=10, z=val) {
return x + y + z;
}
console.log(f(3));
console.log(f(3, 3));
console.log(f(3, 3, 3));
// Output:
// 33
// 26
// 9
Parâmetros Rest
Parâmetros Rest, especificados pelo operador de espalhamento), permitem que você
transforme argumentos consecutivos em uma chamada de função para uma matriz.
Parâmetros Rest eliminam a necessidade do objeto arguments.Parâmetros Rest diferem do
objeto arguments de diversas maneiras, como:
Um parâmetro rest é uma instância de matriz e, portanto, dá suporte a operações que
podem ser executadas em uma matriz.
Um parâmetro rest inclui apenas os argumentos consecutivos que não são
transmitidos como argumentos separados (nomeados) (por outro lado, o objeto
arguments contém todos os argumentos transmitidos para a função).
Importante
Parâmetros Rest e o operador de espalhamento têm suporte apenas no Microsoft Edge.
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 186
No exemplo de código a seguir, true e "hello" são transmitidos como valores de matriz e
armazenados no parâmetro y.O parâmetro rest deve ser o último parâmetro da função.
JavaScript
function f(x, ...y) {
// y is an array.
return x * y.length;
}
console.log(f(3, "hello", true));
// Output:
// 6
Para ver usos adicionais do operador de espalhamento, consulte Operador de Espalhamento.
Objetos e matrizes (JavaScript)
Objetos JavaScript são coleções de propriedades e métodos.Um método é uma função que é
membro de um objeto.Uma propriedade é um valor ou um conjunto de valores (no formato de
uma matriz ou um objeto) que é membro de um objeto.JavaScript suporta quatro tipos de
objetos:
Objetos intrínsecos, como Array e String.
Objetos criados por você.
Objetos de host, como window e document.
Objetos ActiveX.
Propriedades e Métodos Expando
Todos os objetos em JavaScript oferecem suporte a propriedades e métodos expando, que
podem ser adicionadas e removidas em tempo de execução.Essas propriedades e métodos
podem ter qualquer nome e podem ser identificadas por números.Se o nome da propriedade
ou do método for um identificador simples, ele poderá ser escrito depois do nome do objeto
com um ponto final, como myObj.name, myObj.age, e myObj.getAge no código a seguir.
JavaScript
var myObj = new Object();
myObj.name = "Fred";
myObj.age = 42;
myObj.getAge =
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 187
function () {
return this.age;
};
document.write(myObj.name);
document.write("<br/>");
document.write(myObj.age);
document.write("<br/>");
document.write(myObj.getAge());
// Output:
// Fred
// 42
// 42
Se o nome da propriedade ou do método não for um identificador simples ou for
desconhecido na ocasião da gravação do script, você poderá usar uma expressão arbitrária
entre colchetes para indexar a propriedade.Os nomes de todas as propriedades expando em
JavaScript são convertidos em cadeias de caracteres antes de serem adicionados ao objeto.
JavaScript
var myObj = new Object();
// Add two expando properties that cannot be written in the
// object.property syntax.
// The first contains invalid characters (spaces), so must be
// written inside square brackets.
myObj["not a valid identifier"] = "This is the property value";
// The second expando name is a number, so it also must
// be placed inside square brackets
myObj[100] = "100";
Para obter informações sobre como criar um objeto a partir de uma definição, consulte
Criando objetos (JavaScript).
Matrizes como Objetos
No JavaScript, os objetos e as matrizes são manipulados de forma quase idêntica, uma vez que
as matrizes são simplesmenteum tipo especial de objeto.Os objetos e as matrizes podem ter
propriedades e métodos.
As matrizes têm uma propriedade length mas os objetos não.Quando você atribui um valor a
um elemento de uma matriz cujo índice é maior do que o comprimento (por exemplo,
myArray[100] = "hello"), a propriedade length é gerada automaticamente para o novo
tamanho.Da mesma forma, se você tornar a propriedade length menor, qualquer elemento
cujo índice esteja fora do comprimento da matriz será excluído.
JavaScript
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 188
// An array with three elements
var myArray = new Array(3);
// Add some data
myArray[0] = "Hello";
myArray[1] = 42;
myArray[2] = new Date(2000, 1, 1);
document.write("original length is: " + myArray.length);
document.write("<br/>");
// Add some expando properties
myArray.expando = "JavaScript!";
myArray["another Expando"] = "Windows";
// This will still display 3, since the two expando properties
// don't affect the length.
document.write("new length is : " + myArray.length);
// Output:
// original length is: 3
// new length is : 3
Matrizes fornecem métodos para iterar e manipular membros.O exemplo a seguir mostra
como obter as propriedades dos objetos armazenados em uma matriz.
JavaScript
var myArray = new Array(3);
// Add some data
for(var i = 1; i <= 3; i++) {
myArray[i] = new Date(2000 + i, 1, 1);
}
myArray.forEach(function (item) {
document.write(item.getFullYear());
});
// Output:
// 2001
// 2002
// 2003
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 189
Matrizes Multidimensionais
O JavaScript não dá suporte direto a matrizes multidimensionais, mas é possível obter o
comportamento de matrizes multidimensionais armazenando matrizes dentro dos elementos
de outra matriz. (Você pode armazenar qualquer tipo de dados dentro de elementos da matriz,
incluindo outras matrizes.) Por exemplo, o código a seguir cria uma tabela de multiplicação
para números até 5.
JavaScript
// The size of the table.
var iMaxNum = 5;
// Loop counters.
var i, j;
// Set the length of the array to iMaxNum + 1.
// The first array index is zero, not 1.
var MultiplicationTable = new Array(iMaxNum + 1);
// Loop for each major number (each row in the table)
for (i = 1; i <= iMaxNum; i++)
{
// Create the columns in the table
MultiplicationTable[i] = new Array(iMaxNum + 1);
// Fill the row with the results of the multiplication
for (j = 1; j <= iMaxNum; j++)
{
MultiplicationTable[i][j] = i * j;
}
}
document.write(MultiplicationTable[3][4]);
document.write("<br/>");
document.write(MultiplicationTable[5][2]);
document.write("<br/>");
document.write(MultiplicationTable[1][4]);
// Output:
// 12
// 10
// 4
Criando objetos (JavaScript)
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 190
Há várias maneiras para você pode criar seus próprios objetos em JavaScript.Você pode
instanciar diretamente um Objeto Object (JavaScript) e, em seguida, adicionar os seus próprios
métodos e propriedades.Ou pode usar a notação literal de objeto para definir o objeto.Você
também pode usar uma função de construtor para definir um objeto.Para obter mais
informações sobre como usar funções de construtor, consulte Usando construtores para
definir tipos.
Exemplo
O código a seguir mostra como instanciar um objeto e adicionar algumas propriedades.Nesse
caso, apenas o objeto pasta tem as propriedades grain, width e shape.
JavaScript
var pasta = new Object();
pasta.grain = "wheat";
pasta.width = 0.5;
pasta.shape = "round";
pasta.getShape = function() {
return this.shape;
};
document.write(pasta.grain);
document.write("<br/>");
document.write(pasta.getShape());
// Output:
// wheat
// round
Literais de objeto
Você também pode usar a notação literal de objeto para criar apenas uma instância de um
objeto.O código a seguir mostra como instanciar um objeto usando a notação literal de objeto.
JavaScript
var pasta = {
grain: "wheat",
width: 0.5,
shape: "round"
};
Você também pode usar um literal de objeto dentro de um construtor.
Cuidado
Os recursos descritos abaixo têm suporte apenas no Microsoft Edge.
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 191
Em Microsoft Edge, você pode usar a sintaxe abreviada para criar um literal de objeto.
JavaScript
var key = 'a';
var value = 5;
// Older version
var obj1 = {
key: key,
value: value
};
// Edge mode
var obj2 = {key, value};
console.log(obj2);
// Output:
// [object Object] {key: "a", value: 5}
O exemplo a seguir mostra o uso da sintaxe abreviada para definir métodos em literais de
objeto.
JavaScript
// Older versions
var obj = {
method1: function() {},
method2: function() {}
};
// Edge mode
var obj = {
method1() {},
method2() {}
};
Você também pode definir nomes de propriedade dinamicamente em literais de objeto em
Microsoft Edge.O exemplo de código a seguir cria um nome de propriedade para um objeto
dinamicamente usando a sintaxe set.
JavaScript
var propName = "prop_42";
var obj = {
value: 0,
set [propName](v) {
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 192
this.value = v;
}
}
console.log(obj.value);
// Runs the setter property.
obj.prop_42 = 777;
console.log(obj.value);
// Output:
// 0
// 777
O exemplo de código a seguir cria um nome de propriedade para um objeto dinamicamente
usando a sintaxe get.
JavaScript
var propName = "prop_42";
var obj = {
get [propName]() {
return 777;
}
}
console.log(obj.prop_42);
// Output:
// 777
O exemplo de código a seguir cria uma propriedade computada usando a sintaxe de função de
seta para acrescentar 42 ao nome da propriedade.
JavaScript
var obj = {
[ 'prop_' + (() => 42)() ]: 42
};
Exibindo texto em uma página da Web (JavaScript)
Há vários modos de exibir texto nas páginas da Web. Cada um desses modos apresenta
vantagens e desvantagens, e é compatível com usos específicos.
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 193
Exibindo texto
A maneira recomendada para exibir o texto é criar um elemento e gravar sua
propriedade textContent.
JavaScript
<div id="textDiv"></div>
<script type="text/javascript">
var div = document.getElementById("textDiv");
div.textContent = "my text";
var text = div.textContent;
</script>
Nesse exemplo, o valor de text é "my text". Porém, o valor resultante da inclusão ou
configuração da propriedade textContent em um nó pai pode incluir o texto dos nós
filhos. O exemplo a seguir mostra que a propriedade textContent configurada em um
nó filho está incluída no valor da propriedade textContent do nó pai:
JavaScript
<div id="textDiv">
<div id="nested"></div>
</div>
<script type="text/javascript">
var div = document.getElementById("textDiv");
var nestedDiv = document.getElementById("nested");
nestedDiv.textContent = "nested";var text = "[" + div.textContent + "]";
</script>
Nesse exemplo, o valor de text é "[nested]".
Você também pode criar um elemento e gravar suas propriedades innerHTML ou
innerText. A configuração dessas propriedades afeta o texto do elemento em si, mas
não dos elementos filhos. No entanto, essas propriedades também apresentam
algumas desvantagens:
o A propriedade innerText não funciona em todos os navegadores. Por isso,
evite usá-la para não ter problemas de compatibilidade.
o A propriedade innerText é afetada pelos estilos CSS e não será exibida se o
elemento estiver oculto.
o A propriedade innerHTML obtém e define nós aninhados e texto. As
propriedades que não são seguras podem ser usadas em ataques de injeção
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 194
de script. Além disso, quando essa propriedade é definida como texto sem
marcas HTML, todos os nós configurados anteriormente são removidos.
Você pode usar o método document.write sem precisar criar um elemento. No
entanto, esse método limpa toda a página da Web, o que talvez não seja o resultado
desejado.
O exemplo a seguir mostra uma das desvantagens do uso de document.write. O script
deve mostrar a hora a cada cinco segundos, mas mostra apenas duas vezes. Quando
document.write é chamado pela segunda vez, a página já está carregada, e
document.write limpa toda a página ao chamar document.open. Nesse momento, a
função ShowTime já não existe mais.
HTML
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript">
function ShowTime()
{
var dt = new Date();
document.write(dt.toTimeString());
// var elem = document.getElementById("divElem");
// elem.textContent = dt.toTimeString();
window.setTimeout("ShowTime();", 5000);
}
</script>
</head>
<body>
<script type="text/javascript">
ShowTime();
</script>
<div id="myDiv"></div>
</body>
</html>
Para corrigir o código acima, remova a linha que contém document.write e remova os
comentários das duas linhas do código abaixo dela.
Você também pode usar um alert prompt, ou confirm função, que exibe uma
mensagem em uma janela pop-up. Na maioria dos casos, não recomendamos usar
janelas pop-up em um navegador da Web. Grande parte dos navegadores modernos
têm configurações que bloqueiam as janelas pop-up imediatamente. Com isso, é
possível que sua mensagem não seja exibida. Além disso, o uso de janelas pop-up
pode criar um loop infinito, o que impede o usuário de fechar a página da Web como
de costume.
[NODE.JS UMA NOVA ABORDAGEM DA
LINGUAGEM JAVASCRIPT] 20 de março de 2016
Grupo SoftwareOriginSP
Página 195
Ferramentas de utilizadas:
Nodepad++
Geany
Eclipse
Visual Studio Code
Visual Studio for web
Visual Studio 2013
Sites recomendados:
http://wessdevel.blogspot.com.br/2012/08/instalando-e-configurando-nodejs-e.html
https://www.digitalocean.com/community/tutorials/como-instalar-o-node-js-em-um-servidor-
ubuntu-14-04-pt
http://tableless.com.br/o-que-nodejs-primeiros-passos-com-node-js/
https://github.com/ericdouglas/traduz-ai/blob/master/nodejs/001-guia-para-iniciantes-
absolutos-em-nodejs.md
http://www.devmedia.com.br/objetos-e-vetores-em-javascript-conceitos-basicos/29986
https://netbeans.org/kb/docs/webclient/cordova-gettingstarted_pt_BR.html
https://www.ibm.com/developerworks/br/library/j-nodejs/
https://msdn.microsoft.com/pt-br/library/6974wx4d(v=vs.94).aspx
http://nodebr.com/