Aprenda sobre aplicativos em tempo real com o Node.JS criando um
Em um mundo em que o valor do tempo aumenta constantemente, a criação de aplicativos com os quais os usuários possam interagir em tempo real se tornou uma norma para a maioria dos desenvolvedores. A maioria dos aplicativos que vemos hoje, sejam móveis, desktop ou web, tem pelo menos um único recurso em tempo real incluído. Como exemplo, as mensagens e notificações em tempo real são dois dos recursos em tempo real mais usados nos aplicativos.
Neste artigo, apresentamos o desenvolvimento de aplicativos em tempo real usando o Node.js, criando um bate-papo em tempo real. Embora o artigo se concentre nesse caso de uso específico, os conceitos aqui ensinados podem ser aplicados a outros cenários.
De fato, o Node é uma das melhores linguagens de programação disponíveis para criar aplicativos em tempo real devido à sua natureza assíncrona e orientada a eventos. Antes de começar a construir um aplicativo em tempo real, veremos que tipo de aplicativos em tempo real podemos criar usando o Node.js. Se você quiser conhecer mais outras áreas em que o Node.js se destaca ou simplesmente fica aquém, leia meu artigo Quando você deve e não deve usar o Node.js. para seu projeto .
Onde os aplicativos em tempo real são usados?
Como mencionei acima, a entrega de mensagens e notificações são dois dos casos de uso mais comuns para aplicativos em tempo real. Mas podemos usar aplicativos em tempo real para uma infinidade de outros propósitos. Vamos ver o que são.
Mensagens em tempo real
A maioria de nós está familiarizada com o uso de aplicativos de mensagens em tempo real, especialmente em dispositivos móveis, na forma de Whatsapp, Facebook Messenger e vários outros aplicativos de mensagens. No entanto, as mensagens em tempo real não são limitadas a aplicativos de mensagens puramente. Vemos recursos de mensagens em tempo real em aplicativos de táxi sob demanda, aplicativos de entrega e plataformas colaborativas.
Entrega de Notificação em Tempo Real
A ativação de notificações em tempo real provou ser uma virada no jogo quando se trata de aumentar o envolvimento do usuário com os aplicativos. Por esse motivo, dificilmente você veria um aplicativo moderno que não entrega notificações em tempo real para seus usuários.
Transmissão ao vivo
As transmissões ao vivo com as quais os usuários podem interagir em tempo real estão se tornando cada vez mais populares depois que as plataformas de mídia social integram as transmissões de vídeo ao vivo a seus aplicativos. Os recursos de transmissão ao vivo do Instagram e do Facebook são os melhores exemplos disso.
Rastreamento em tempo real
Com a introdução de aplicativos populares de táxi e entrega, como Uber e Amazon, acompanhar o progresso das viagens ou entregas de táxi dos usuários em tempo real tornou-se um requisito essencial. Suas atualizações de progresso em tempo real aumentam a usabilidade e a confiabilidade desses aplicativos.
Dispositivos IoT
Recursos em tempo real são essenciais para dispositivos IoT. Os dados capturados pelos sensores colocados nos dispositivos IoT são transmitidos, processados e exibidos aos usuários finais com um atraso mínimo. Como a maioria das entradas capturadas por esses dispositivos, como temperatura e iluminação, muda constantemente com o tempo, os aplicativos que trabalham com dispositivos IoT devem poder receber e enviar dados em tempo real.
Como podemos criar aplicativos em tempo real?
A criação de um aplicativo em tempo real é diferente da criação de um aplicativo Web normal? A resposta é sim.
Pense em um aplicativo de mensagens em que os usuários possam enviar mensagens em tempo real. Essas mensagens devem aparecer no aplicativo de outros usuários assim que as mensagens forem enviadas. Se implementarmos esse aplicativo como um aplicativo Web normal, onde apenas o cliente pode iniciar solicitações ao servidor para receber dados, o usuário deverá atualizar a página da Web regularmente para ver as mensagens mais recentes ou o lado do cliente deve enviar solicitações AJAX para o servidor em curtos intervalos de tempo para recuperar as mensagens mais recentes. O primeiro dos dois não é muito fácil de usar e o segundo é um desperdício de recursos do aplicativo. Então, claramente, precisamos ter um método diferente para criar aplicativos em tempo real que faça mais sentido.
O WebSocket fornece a solução que precisamos. O WebSocket é um protocolo de comunicação que permite ao cliente e ao servidor iniciar a comunicação. Em outras palavras, com o WebSocket, o servidor pode enviar dados para o cliente a qualquer momento, sem que o cliente precise solicitar dados primeiro. No caso do aplicativo de mensagens anterior, podemos usar o WebSockets para enviar instantaneamente mensagens para todos os usuários através do servidor. Podemos usar a API WebSocket para se comunicar usando WebSockets ao criar aplicativos.
Socket.io
No entanto, ao implementar um aplicativo em tempo real usando o Node, não precisamos usar diretamente a API WebSocket. Em vez disso, a biblioteca Javascript e Node.js.Socket.io, que é uma API da API WebSocket, fornece uma implementação muito mais simples do WebSockets para uso. Neste tutorial, usaremos o Socket.io para criar e gerenciar conexões WebSocket entre o cliente e o servidor.
Criando uma sala de bate-papo em tempo real com o Node.js
Agora que falamos sobre o desenvolvimento de aplicativos em tempo real, podemos começar a criar nosso próprio aplicativo em tempo real. Neste tutorial, vamos construir uma sala de bate-papo simples que os usuários podem usar para se comunicar com outros usuários conectados. Qualquer número de usuários pode se conectar à sala de bate-papo e as mensagens enviadas por um usuário tornam-se instantaneamente visíveis a todos os usuários conectados à sala de bate-papo.
Nossa sala de chat simples terá o seguinte conjunto de recursos.
- Alterar o nome de usuário do usuário
- Enviar mensagens
- Mostrar se outro usuário está digitando uma mensagem
Legal, agora que temos nossos requisitos, vamos começar a criar o ambiente e a configurar a estrutura
Configurando o ambiente de aplicativos
Primeiro, crie um novo diretório para o aplicativo. Em seguida, execute the npm init
para configurar o package.json
arquivo. Certifique-se de que, nesta etapa, você atribua app.js
como seu script principal; caso contrário, não se preocupe, você sempre poderá alterá-lo package.json
posteriormente.
Instalar dependências
Neste tutorial, estamos usando os pacotes express, ejs, socket.io e nodemon para criar o aplicativo.
- Ejs é um mecanismo de modelo JS popular
- Discutimos o uso do socket.io anteriormente
- O Nodemon é um pacote que reinicia o servidor toda vez que fazemos uma alteração no código do aplicativo. Isso elimina a necessidade de parar e iniciar manualmente o servidor toda vez que fazemos uma alteração. Diferentemente dos outros pacotes, instalamos o nodemon como uma dependência de desenvolvimento, uma vez que o usamos apenas para fins de desenvolvimento.
Instale express, ejs e socket.io usando o seguinte comando.
npm install express ejs socket.io --save
Instale o nodemon como uma dependência de desenvolvimento usando este comando.
npm install nodemon --save-dev
Para iniciar o aplicativo com nodemon, devemos adicionar um script de início ao nosso arquivo package.json.
"scripts": {
"start": "nodemon app.js",
},
Em seguida, podemos iniciar o aplicativo executando o seguinte comando na linha de comando.
npm run start
Se falhar, não se preocupe, é basicamente porque ainda não temos nenhum arquivo de código.
Configure a estrutura do aplicativo
Com todas as dependências necessárias para este projeto instaladas, vamos criar o aplicativo na estrutura do projeto. Para isso, você precisará criar alguns diretórios e, por enquanto, um arquivo chamado app.js
. Vamos fazer isso para que a estrutura do seu aplicativo tenha a seguinte aparência:
|--app.js
|--views
|--node_modules
|--package.json
|--public
|--css
|--js
Eu acho que a estrutura é bem clara, mas vamos repassar rapidamente:
app.js
: file que usaremos para hospedar nosso código do lado do servidorviews
: pasta contendo as visualizações (ejs)node_modules
: onde instalamos nossas dependênciaspackage.json
arquivo de configuração npmpublic
: diretório que usaremos para armazenar nossos ativos, como arquivos css, arquivos javascript (para o lado do cliente) e imagens.
Primeiros passos construindo o servidor
O primeiro que precisamos fazer antes mesmo de pensar em fazer as conexões em tempo real é começar express
a funcionar, para isso, vamos abrir nosso app.js
arquivo e colar o seguinte código:
const express = require('express')
const socketio = require('socket.io')
const app = express()
app.set('view engine', 'ejs')
app.use(express.static('public'))
app.get('/', (req, res)=> {
res.render('index')
})
const server = app.listen(process.env.PORT || 3000, () => {
console.log("server is running")
})
Depois de express
configurar e usar ejs
como sistema de modelo, podemos começar a trabalhar na inicialização do sockets.io. Para isso, adicione o seguinte código no final do seu app.js
arquivo.
//initialize socket for the server
const io = socketio(server)
io.on('connection', socket => {
console.log("New user connected")
})
O código é bastante simples: estamos inicializando a socket.io
partir de nossa server
conexão (expressa) e, em seguida, configuramos um uso uniforme io.on()
que será acionado toda vez que uma nova conexão com o soquete for estabelecida.
Se você agora executar seu servidor npm start
, poderá receber novas conexões de soquete. Então, vamos começar a construir nosso front-end.
Construindo nosso front-end
Nós não gastar muito tempo fazendo o nosso olhar front-end incrível, mas vamos explicar como a conexão com as obras de servidor, como emit
e capture
eventos de soquete e vamos aplicar tudo isso em nosso exemplo chat.
Vamos começar criando um modelo em nossa pasta views, para isso crie um index.ejs
arquivo e cole o seguinte código:
<!DOCTYPE html>
<head>
<title>Simple realtime chatroom</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css">
</head>
<body>
<div class="container">
<div class="title">
<h3>Realtime Chat Room</h3>
</div>
<div class="card">
<div class="card-header">Anonymous</div>
<div class="card-body">
<div class="input-group">
<input type="text" class="form-control" id="username" placeholder="Change your username" >
<div class="input-group-append">
<button class="btn btn-warning" type="button" id="usernameBtn">Change</button>
</div>
</div>
</div>
<div class="message-box">
<ul class="list-group list-group-flush" id="message-list"></ul>
<div class="info"></div>
</div>
<div class="card-footer">
<div class="input-group">
<input type="text" class="form-control" id="message" placeholder="Send new message" >
<div class="input-group-append">
<button class="btn btn-success" type="button" id="messageBtn">Send</button>
</div>
</div>
</div>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.0.4/socket.io.js"></script>
<script src="/js/chatroom.js"></script>
</body>
</html>
Observe como incluímos o script da biblioteca socket.io do lado do cliente e o arquivo javascript personalizado que vamos usar neste código.
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.0.4/socket.io.js"></script>
<script src="/js/chatroom.js"></script>
Também temos um botão com ID messageBtn
para enviar uma nova mensagem e outro botão com ID usernameBtn
para enviar um novo nome de usuário. As entradas de nome de usuário e mensagem têm IDs username
e message
respectivamente. Espera-se que todas as mensagens do usuário apareçam dentro da lista não ordenada com o ID message-list
. Se um usuário estiver amarrando uma mensagem, essas informações aparecerão dentro da div com classe info
.
Se você abrir o navegador e acessar http://localhost:3000/
o aplicativo, será algo como isto:
Mas não está fazendo nada, os botões não funcionarão e serão praticamente um aplicativo estático. Então, a seguir, vamos começar a conectar o front-end ao servidor.
Para isso, crie um novo arquivo Javascript chamado chatroom.js
dentro da pasta js (observe no HTML acima, que eu já estou fazendo referência a esse arquivo) do diretório público. Dentro do arquivo Javascript, precisamos nos conectar ao soquete do front-end. Nós podemos fazer assim.
(function connect(){
let socket = io.connect('http://localhost:3000')
})()
Visite seu site novamente e em seu terminal (no lado do servidor) você verá algo como:
Impressionante! seu aplicativo já está funcionando, embora não faça muito. Vamos construir a funcionalidade a seguir
Alterando o nome do usuário
O nome de usuário padrão que usamos para todas as conexões é “Anônimo”. Damos aos usuários a opção de alterar esse nome de usuário. Configuraremos o back-end para alterar o nome de usuário quando o front-end emitir um change_username
evento. Volte para o código do servidor ( app.js
) e edite seu connection
evento para adicionar um novo código.
io.on('connection', socket => {
console.log("New user connected")
socket.username = "Anonymous"
socket.on('change_username', data => {
socket.username = data.username
})
})
Em seguida, precisamos ajustar nosso front-end, para que, ao pressionar o botão alterar nome de usuário, ele emita um evento para o servidor com o nome change_username
. Veja como criamos o nome emitindo e capturando o mesmo nome de evento?
Dentro chatroom.js
, vamos adicionar um ouvinte de evento usernameBtn
para emitir um change_username
evento quando o botão for clicado.
(function connect(){
let socket = io.connect('http://localhost:3000')
let username = document.querySelector('#username')
let usernameBtn = document.querySelector('#usernameBtn')
let curUsername = document.querySelector('.card-header')
usernameBtn.addEventListener('click', e => {
console.log(username.value)
socket.emit('change_username', {username: username.value})
curUsername.textContent = username.value
username.value = ''
})
})()
Agora, se você recarregar a página da web e enviar um novo nome de usuário, verá o seu nome de usuário atual alterado para o novo. Em seguida, vamos começar a enviar mensagens.
Enviando Mensagens
O próximo recurso que vamos implementar é o envio de mensagens. Aqui as coisas começam a ficar um pouco diferentes, até agora dissemos que toda vez que o front-end emite uma mensagem, o servidor a recebe, no entanto, no nosso novo caso, o front-end precisa emitir um new_message
evento, que precisará para ser enviado a todos os clientes conectados, para que eles possam imprimir a nova mensagem.
Primeiro, configuraremos o front-end para emitir um new_message
evento quando uma nova mensagem for enviada. Como o lado do cliente também deve ser configurado para receber novas mensagens que outros usuários enviam do servidor, o aplicativo também deve escutar receive_message
eventos no front-end e mostrar a nova mensagem na página da Web adequadamente. Podemos realizar essas duas tarefas usando o código a seguir que entra na connect
função anterior em chatroom.js
.
let message = document.querySelector('#message')
let messageBtn = document.querySelector('#messageBtn')
let messageList = document.querySelector('#message-list')
messageBtn.addEventListener('click', e => {
console.log(message.value)
socket.emit('new_message', {message: message.value})
message.value = ''
})
socket.on('receive_message', data => {
console.log(data)
let listItem = document.createElement('li')
listItem.textContent = data.username + ': ' + data.message
listItem.classList.add('list-group-item')
messageList.appendChild(listItem)
})
Sempre que o receive_message
evento acontece no lado do cliente, alteramos nosso DOM para renderizar a mensagem na tela.
No lado de back-end, quando recebemos um new_message
evento, precisamos emitir um novo evento para todos os clientes, para isso usamos a io.sockets.emit()
função. Altere seu connection
evento no seu app.js
arquivo da seguinte maneira:
io.on('connection', socket => {
console.log("New user connected")
socket.username = "Anonymous"
socket.on('change_username', data => {
socket.username = data.username
})
//handle the new message event
socket.on('new_message', data => {
console.log("new message")
io.sockets.emit('receive_message', {message: data.message, username: socket.username})
})
})
Ao manipular o new_message
evento, o próprio servidor emite um receive_message
evento para os clientes conectados com dados sobre a nova mensagem. Este evento é recebido por todos os usuários conectados ao servidor, incluindo aquele que enviou a mensagem, para que a nova mensagem seja exibida em suas interfaces de sala de bate-papo.
Se agora você abrir o aplicativo da web no navegador (você pode ter várias instâncias), poderá começar a conversar (com você mesmo?: P)
Você pode se conectar à sala de bate-papo usando dois navegadores separados e brincar com o recurso de envio de mensagens e ver como as mensagens que um usuário envia aparecem instantaneamente nas interfaces de aplicativos dos dois usuários.
Estou digitando ….
Na maioria dos aplicativos de mensagens em tempo real que usamos hoje, vemos um texto simples que diz “o usuário X está digitando …” sempre que outro usuário digita uma mensagem. Isso dá ao aplicativo uma sensação mais em tempo real e melhora a experiência do usuário. Nós vamos adicionar esse recurso ao nosso aplicativo.
Primeiro, vamos considerar a implementação do front-end. Nós adicionamos um novo ouvinte de evento à caixa de entrada de mensagem para emitir um typing
evento sempre que um pressionamento de tecla ocorre. Se as teclas pressionadas na caixa de entrada de mensagens indicam que o usuário está digitando uma mensagem, o typing
evento informa ao servidor que o usuário está digitando uma mensagem. O lado do cliente também escuta os typing
eventos emitidos pelo servidor para saber se outro usuário está digitando uma mensagem no momento e mostrá-la na interface do usuário.
Novamente, dentro da função connect chatroom.js
, adicionamos o código a seguir.
let info = document.querySelector('.info')
message.addEventListener('keypress', e => {
socket.emit('typing')
})
socket.on('typing', data => {
info.textContent = data.username + " is typing..."
setTimeout(() => {info.textContent=''}, 5000)
})
Se um usuário estiver digitando uma mensagem, outros usuários receberão o texto ” está digitando …” por 5 segundos.
Agora, precisamos configurar o back-end para lidar com eventos de digitação. O código que usamos aqui é este.
socket.on('typing', data => {
socket.broadcast.emit('typing', {username: socket.username})
})
Aqui, o socket.io usa a broadcast
função para notificar os clientes conectados. Quando usamos broadcast
, todos os usuários, exceto quem está digitando a mensagem, recebem o evento de digitação do servidor. Portanto, todo usuário, exceto aquele que digita a mensagem, é mostrado no texto ” está digitando …”.
Mais uma vez, você pode se conectar à sala de bate-papo a partir de dois navegadores e ver como isso funciona em tempo real.
Impressionante!
Resumo
Hoje, o uso de recursos em tempo real com aplicativos para desktop, dispositivos móveis e Web quase se tornou uma necessidade. Neste artigo, abordamos vários aplicativos de aplicativos em tempo real e aprendemos a criar uma sala de bate-papo em tempo real com a ajuda do Node.js. e do Socket.io. Para continuar a partir daqui, você pode tentar melhorar essa sala de chat adicionando mais recursos e usando um banco de dados para persistir em mensagens mais antigas ou implementar outro aplicativo em tempo real com um caso de uso diferente.
Obrigado pela leitura!