How Real-Time Communication in Web Development Made
By: Bilal Rifas
Tags: Programming, JavaScript, UX, Web Development, Nodejs

WebSockets vs HTTP

So, does it mean it’s impossible to create a chat application without WebSockets?

Well, there is a technique called HTTP Long Polling. Using this, the client sends a request and the server holds that opened until some new data is available. As soon as data appears and the client receives it, a new request is immediately sent and operation is repeated over and over again. However, a pretty big disadvantage of using HTTP Long Polling is that it consumes a lot of server resources.

Socket.io — Building a Chat App

Below, I’ll present to you a brief Socket.io tutorial on how to create a simple chat application with Vanilla JS frontend part and Node.js server. You need to create a project with the default package.json file.

Having this created, you need to set up a server and install all the needed dependencies. In order to do it, you need to create an index.js file and install socket.io and express. You can use the following command:

touch index.js && npm install express socket.io && npm install --save-dev nodemon

In index.js , you need to set up a local server and basic socket connection.

And basically, that’s all you have to do on the backend side at the moment. Once you make a proper request, the connection should be established. It will be visible through the logged message as shown below.

const express = require(“express”);

const socket = require(“socket.io”);



// App setup

const PORT = 5000;

const app = express();

const server = app.listen(PORT, function () {

console.log(`Listening on port ${PORT}`);

console.log(`http://localhost:${PORT}`);

});



// Static files

app.use(express.static(“public”));



// Socket setup

const io = socket(server);

io.on(“connection”, function (socket) {

console.log(“Made socket connection”);

});

Time to prepare the frontend

Let’s start by creating the public folder and the following files: index.html , main.js . Optionally, you can add style.css .

Below, you can see the index.html scaffold. Basically, all you need are HTML tags you can refer to and some scripts from Socket.io included in the project. That’s how your index.html file should look with the WebSockets scripts included.

<!DOCTYPE html>

<html lang=”en”>

<head>

<meta charset=”UTF-8" />

<meta name=”viewport” content=”width=device-width, initial-scale=1.0" />

<title>Socket.io simple chat</title>

<link rel=”stylesheet” href=”./style.css” /> </head>

<body>

<div class=”container”>

<div class=”inbox”>

<div class=”inbox__people”>

<h4>Active users</h4>

</div>

<div class=”inbox__messages”>

<div class=”messages__history”></div>

<div class=”fallback”></div>

</div>

</div>

<form class=”message_form”>

<input type=”text” class=”message_form__input” placeholder=”Type a message” />

<button class=”message_form__button” type=”submit”> Enter </button>

</form>

</div>

<script

src=”https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.3.0/socket.io.js”></script>

<script src=”main.js”></script>

</body>

</html>

Then, you need to set up the connection on the frontend side. The only line of code you need in main.js is const socket = io(); . As you can see once the page is opened and the script is loaded, the connection is established. The next thing you need to do is to handle a new user connection, a new message, and last but not least a currently typing user.

In socket, there are two ways of emitting events. One way is from the user to everyone and the other which emits an event to all the other instances. The idea is to display the list of all the active users. So, when a user connects they need to inform about it and get the list of users who are already active.

const activeUsers = new Set();



io.on(“connection”, function (socket) {

console.log(“Made socket connection”);



socket.on(“new user”, function (data) {

socket.userId = data;

activeUsers.add(data);

io.emit(“new user”, […activeUsers]);

}); socket.on(“disconnect”, () => {

activeUsers.delete(socket.userId);

io.emit(“user disconnected”, socket.userId);

}); });

When a user connects they emit the event which includes the information about their username. You should set the property of userId on the socket. It will be needed when the user disconnects. To do that you need to add a username to the Set of active users and emit an event with a list of all active users.

In the main.js I created two functions and two socket listeners.

const socket = io();

const inboxPeople = document.querySelector(“.inbox__people”); let userName = “”;

const newUserConnected = (user) => {

userName = user || `User${Math.floor(Math.random() * 1000000)

}`; socket.emit(“new user”, userName);



addToUsersBox(userName);};



const addToUsersBox = (userName) => {

if (!!document.querySelector(`.${userName}-userlist`)) {

return;

}

const userBox = `<div class=”chat_ib ${userName}-userlist” <h5>${userName}</h5> </div>`;

inboxPeople.innerHTML += userBox;

};



// new user is created so we generate nickname and emit eventnewUserConnected(); socket.on(“new user”, function (data) {

data.map((user) => addToUsersBox(user));

});



socket.on(“user disconnected”, function (userName) {

document.querySelector(`.${userName}-userlist`).remove();

});

Since we handled the way users can connect and disconnect, now it’s time we handle the new messages. On the server-side you do nothing more than adding the listener shown below.

socket.on(“chat message”, function (data) {

io.emit(“chat message”, data);

});

On the client side you need to do a few more things, as per the example below.

const inputField = document.querySelector(“.message_form__input”);

const messageForm = document.querySelector(“.message_form”);

const messageBox = document.querySelector(“.messages__history”); const addNewMessage = ({ user, message }) => {

const time = new Date();

const formattedTime = time.toLocaleString(“en-US”, { hour: “numeric”, minute: “numeric” });



const receivedMsg = `

<div class=”incoming__message”>

<div class=”received__message”>

<p>${message}</p>

<div class=”message__info”>

<span class=”message__author”>${user}</span>

<span class=”time_date”>${formattedTime}</span>

</div>

</div>

</div>`; const myMsg = `

<div class=”outgoing__message”>

<div class=”sent__message”>

<p>${message}</p>

<div class=”message__info”>

<span class=”time_date”>${formattedTime}</span>

</div>

</div>

</div>`;



messageBox.innerHTML += user === userName ? myMsg : receivedMsg;

};



messageForm.addEventListener(“submit”, (e) => {

e.preventDefault(); if (!inputField.value) {

return;

}



socket.emit(“chat message”, {

message: inputField.value,

nick: userName,

});



inputField.value = “”;});



socket.on(“chat message”, function (data) {

addNewMessage({

user: data.nick,

message: data.message

});

});

The function responsible for displaying new messages is triggered right after receiving information from a socket. The message is pushed to the server in the listener function of the form submit. You just need to check if the client is a message author or not.

I hope that this brief Socket.io tutorial helped you understand how simple is using this approach. And how many interesting things you can do with JavaScript and basic Node.js knowledge.