Make changes instantly PHP or Javascript [duplicate] - javascript

This question already has answers here:
Short-polling vs Long-polling for real time web applications?
(3 answers)
Closed 12 months ago.
I have a chat system but I want both the notifications and the messages to be updated immediately, I am using this code (setInterval) but it makes requests every 500 seconds so I think it is not very efficient, is there another way to do it?
setInterval(() => {
let xhr = new XMLHttpRequest();
xhr.open("POST", "INCLUDES/funciones/get-chat.php", true);
xhr.onload = () => {
if (xhr.readyState === XMLHttpRequest.DONE) {
if (xhr.status === 200) {
let data = xhr.response;
chatBox.innerHTML = data;
if (!chatBox.classList.contains("active")) {
}
}
}
}
let formData = new FormData(form);
xhr.send(formData);
}, 500);

You should check WebSockets. You can lower the time between requests lowering the second parameter of setInterval but that would be bad. It would be a huge stress for your server that see a spike in the number of requests.
WebSocket, as the name said, open a socket, a permanent comunication channel between the server and client. This allows the server to send messages to the client.
The advantage is that if no message is ready for the client no traffic is sent and no new requests are made from the client to the server.
This is not the right place for a full chat code example because it's quite long. You can see Socket.io not the fastest but maybe the easiest library to work with WebScokets. Here you can find an example of a working chat (server and client) using Socket.IO

Related

WebSocket needs browser refresh to update list

My project works as intended except that I have to refresh the browser every time my keyword list sends something to it to display. I assume it's my inexperience with Expressjs and not creating the route correctly within my websocket? Any help would be appreciated.
Browser
let socket = new WebSocket("ws://localhost:3000");
socket.addEventListener('open', function (event) {
console.log('Connected to WS server')
socket.send('Hello Server!');
});
socket.addEventListener('message', function (e) {
const keywordsList = JSON.parse(e.data);
console.log("Received: '" + e.data + "'");
document.getElementById("keywordsList").innerHTML = e.data;
});
socket.onclose = function(code, reason) {
console.log(code, reason, 'disconnected');
}
socket.onerror = error => {
console.error('failed to connect', error);
};
Server
const ws = require('ws');
const express = require('express');
const keywordsList = require('./app');
const app = express();
const port = 3000;
const wsServer = new ws.Server({ noServer: true });
wsServer.on('connection', function connection(socket) {
socket.send(JSON.stringify(keywordsList));
socket.on('message', message => console.log(message));
});
// `server` is a vanilla Node.js HTTP server, so use
// the same ws upgrade process described here:
// https://www.npmjs.com/package/ws#multiple-servers-sharing-a-single-https-server
const server = app.listen(3000);
server.on('upgrade', (request, socket, head) => {
wsServer.handleUpgrade(request, socket, head, socket => {
wsServer.emit('connection', socket, request);
});
});
In answer to "How to Send and/or Stream array data that is being continually updated to a client" as arrived at in comment.
A possible solution using WebSockets may be to
Create an interface on the server for array updates (if you haven't already) that isolates the array object from arbitrary outside modification and supports a callback when updates are made.
Determine the latency allowed for multiple updates to occur without being pushed. The latency should allow reasonable time for previous network traffic to complete without overloading bandwidth unnecessarily.
When an array update occurs, start a timer if not already running for the latency period .
On timer expiry JSON.stringify the array (to take a snapshot), clear the timer running status, and message the client with the JSON text.
A slightly more complicated method to avoid delaying all push operations would be to immediately push single updates unless they occur within a guard period after the most recent push operation. A timer could then push modifications made during the guard period at the end of the guard period.
Broadcasting
The WebSockets API does not directly support broadcasting the same data to multiple clients. Refer to Server Broadcast in ws documentation for an example of sending data to all connected clients using a forEach loop.
Client side listener
In the client-side message listener
document.getElementById("keywordsList").innerHTML = e.data;
would be better as
document.getElementById("keywordsList").textContent = keywordList;
to both present keywords after decoding from JSON and prevent them ever being treated as HTML.
So I finally figured out what I wanted to accomplish. It sounds straight forward after I learned enough and thought about how to structure the back end of my project.
If you have two websockets running and one needs information from the other, you cannot run them side by side. You need to have one encapsulate the other and then call the websocket INSIDE of the other websocket. This can easily cause problems down the road for other projects since now you have one websocket that won't fire until the other is run but for my project it makes perfect sense since it is locally run and needs all the parts working 100 percent in order to be effective. It took me a long time to understand how to structure the code as such.

How to catch and deal with "WebSocket is already in CLOSING or CLOSED state" in Node

I've been searching for a solution to the issue "WebSocket is already in CLOSING or CLOSED state" and found this:
Meteor WebSocket is already in CLOSING or CLOSED state error
WebSocket is already in CLOSING or CLOSED state.
Answer #1 is for strictly related to Meteor and #2 has no answers... I have a Node server app with a socket:
const WebSocket = require('ws');
const wss = new WebSocket.Server({ server });
wss.on('connection', function connection(socket) {
socket.on('message', function incoming(data) {
console.log('Incoming data ', data);
});
});
And clients connect like this:
const socket = new WebSocket('ws://localhost:3090'); //Create WebSocket connection
//Connection opened
socket.addEventListener('open', function(event) {
console.log("Connected to server");
});
//Listen to messages
socket.addEventListener('message', function(event) {
console.log('Message from server ', event);
});
However after a few minutes, clients randomly disconnect and the function
socket.send(JSON.stringify(data));
Will then throw a "WebSocket is already in CLOSING or CLOSED state.".
I am looking for a way to detect and deal these disconnections and immediately attempt to connect again.
What is the most correct and efficient way to do this?
The easiest way is to check if the socket is open or not before sending.
For example - write a simple function:
function isOpen(ws) { return ws.readyState === ws.OPEN }
Then - before any socket.send make sure it is open:
if (!isOpen(socket)) return;
socket.send(JSON.stringify(data));
You can also rewrite the send function like this answer but in my way you can log this situations.
And, for your second request
immediately attempt to connect again
There is no way you can do it from the server.
The client code should monitor the WebSocket state and apply reconnect method based on your needs.
For example - check this VueJS library that do it nicely. Look at Enable ws reconnect automatically section
Well, my answer is simple, is just you send message to the web socket in an interval of time, to understand that you are using the service. It is better than you got another connection. Now, you start your project where are the web socket function and inspect elements to see the state Time, and see the time that change of "pending" for the time when closes. So now you will define a media of interval to make a setInterval functions like this for example: enter code here
const conn = WebSocket("WSS://YourLocationWebSocket.com");
setInterval(function(){
var object = {"message":"ARandonMessage"};
object = JSON.stringify(object);
conn.send(object);
},/*The time, I suggest 40 seconds, so*/ 40000)
might be late to the party, but i recently encountered this problem & figured that the reason is because the readystate property of the websocket connection is 3 (CLOSING) https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/readyState at the time the message was sent.
i resolved this by checking the readystate property; if it equals to 3, close and reinitialize the websocket connection. then do a while loop that exits when the readystate property equals to 1, otherwise a delay, to ensure that the new connection is already open.
if ( this.ws.readyState === 3 ) {
this.ws.close();
this.ws = new WebSocket(`wss://...`);
// wait until new connection is open
while (this.ws.readyState !== 1) {
await new Promise(r => setTimeout(r, 250));
}
}
this.ws.send(...)

receive multiple responses in javascript with one request

How can I receive multiple responses from a server using javascript.
I have a requirement where a request is posted one time with the data and number of iterations and at server side the request is processed for the number of iterations. On completion of each iteration the server sends back the response. So for one request and 10 iterations my java script need to receive the 10 responses and show it on the web page. Is there any way that I can handle this using javascript. I cannot use any other technology.
Right now I am using the following way
function showResponse(){
xmlHttp = GetXmlHttpObject();
var dataString = document.getElementById("request-parameters").value;
var iterations = document.getElementById("iterations").value;
if(xmlHttp==null){
alert("your browser does not support AJAX!");
}
var url = "http://localhost:8080/servlet/requestServlet";
xmlHttp.onreadystatechange=stateChanged;
xmlHttp.open("POST",url,true);
xmlHttp.send(dataString);
}
function GetXmlHttpObject(){
var xmlHttp=null;
try{
//Firefox, Opera, Safari
xmlHttp=new XMLHttpRequest();
}catch(e){
//IE
try{
xmlHttp=new ActiveXObject("Msxml2.XMLHTTP");
}catch(e){
xmlHttp=new ActiveXObject("Microsoft.XMLHTTP");
}
}
return xmlHttp;
}
function stateChanged(){
if(xmlHttp.readyState==4){
if(xmlHttp.status == 200){
var resp = xmlHttp.responseText;
var responseDiv = document.getElementById("response");
responseDiv.innerHTML=responseDiv.innerHTML+resp1[1];
}
}
}
I cannot modify this approach. Is it possible to get it done with XmlHttp object.
With just 'basic javascript' you cannot do this.
It just works like this: Client sends request, servers returns 'something'. The server cannot simply keep sending data back to this client for multiple reasons. A: There is not a 'link' aka connection between both party's except for the first 'call' of a request, but the client just waits for the response.
B: The script does not expect an other answer back.
What you need is a websocket for example. This way the client can listen to the server and actually process data send from the server to the client.
So in short:
Javascript works always like this:
Client -> Server | and the server respond back
For a socket you can have:
Client -> Server
Server -> Client
You can use some sort of 'javascript' even tho its a different technology.. like NodeJS.
The other way is to make a loop. Rather than posting a dataset with an amount of iterations, just iterate it in JS and for each iteration send it to the server to actually 'perform' on your data.
1) HTTP Try request once to one controller, and then get answer from other controller, you can do this with jQuery or with native XmlHttpRequest (it is not one request).
$.get("server/controllerJob",{data:"data"});
var askInterval = window.setInterval(function(){
$.get("server/askAnswerFromJob",{data:"data"}).done(function( data ) {
if(data.complete){
/** do staff**/
window.clearInterval(askInterval);
}else{
/** do staff**/
}
});
},200);
2) webSocket Or try to find something about WebSocket webSocket documentation, it is techonolgy with one connection with multiple request and response (full-duplex connection stream).
Also you need other server controller realization and see websocket
supported browsers
Notice the ws:. This is the new URL schema for WebSocket connections.
There is also wss: for secure WebSocket connection the same way https:
is used for secure HTTP connections
I'm only just noticing that the "examples" web app that comes with
Tomcat 7 contains 4 complete examples of how to use WebSocket (for java developers)
var connection = new WebSocket('ws://server/yourService',['soap','xmpp']);
connection.onopen = function () {
connection.send('ask'); // Send the message to server
};
//Each time on new messages from server, this callbacks will be executed (depends on result)
// Log errors from server
connection.onerror = function (error) {
console.log('WebSocket Error ' + error);
};
// Get messages from the server
connection.onmessage = function (e) {
console.log('Answer: ' + e.data);
};

webdis connection time for second client

I am using webdis (https://github.com/nicolasff/webdis) I ran the webdis as directed in the website and included the following javascript code to connect:
var previous_response_length = 0
xhr = new XMLHttpRequest()
xhr.open("GET", "http://localhost:7379/SUBSCRIBE/hello", true);
xhr.onreadystatechange = checkData;
xhr.send(null);
function checkData() {
if(xhr.readyState == 3) {
response = xhr.responseText;
chunk = response.slice(previous_response_length);
previous_response_length = response.length;
console.log(chunk);
}
};
When I open up the connection in a web page and opens up two tabs, it takes the secondly opened tab about 10 seconds to start subscribing and listening to messages published. Is there anyway to reduce that wait time for the second client to connect and make it instant? Anything I could add?

Can't close server (nodeJS)

Why I can't close the server by requesting localhost:13777/close in browser (it continues to accept new requests), but it will gracefully close on timeout 15000? Node version is 0.10.18. I fell into this problem, trying to use code example from docs on exceptions handling by domains (it was giving me 'Not running' error every time I secondly tried to request error page) and finally came to this code.
var server
server = require("http").createServer(function(req,res){
if(req.url == "/close")
{
console.log("Closing server (no timeout)")
setTimeout(function(){
console.log("I'm the timeout")
}, 5000);
server.close(function(){
console.log("Server closed (no timeout)")
})
res.end('closed');
}
else
{
res.end('ok');
}
});
server.listen(13777,function(){console.log("Server listening")});
setTimeout(function(){
console.log("Closing server (timeout 15000)")
server.close(function(){console.log("Server closed (timeout 15000)")})
}, 15000);
The server is still waiting on requests from the client. The client is utilizing HTTP keep-alive.
I think you will find that while the existing client can make new requests (as the connection is already established), other clients won't be able to.
Nodejs doesn't implement a complex service layer on top of http.Server. By calling server.close() you are instructing the server to no longer accept any "new" connections. When a HTTP Connection:keep-alive is issued the server will keep the socket open until the client terminates or the timeout is reached. Additional clients will not be able to issue requests
The timeout can be changed using server.setTimeout() https://nodejs.org/api/http.html#http_server_settimeout_msecs_callback
Remember if a client has created a connection before the close event that connection can continually be used.
It seems that a lot of people do not like this current functionality but this issue has been open for quite a while:
https://github.com/nodejs/node/issues/2642
As the other answers point out, connections may persist indefinitely and the call to server.close() will not truly terminate the server if any such connections exist.
We can write a simple wrapper function which attaches a destroy method to a given server that terminates all connections, and closes the server (thereby ensuring that the server ends nearly immediately!)
Given code like this:
let server = http.createServer((req, res) => {
// ...
});
later(() => server.close()); // Fails to reliably close the server!
We can define destroyableServer and use the following:
let destroyableServer = server => {
// Track all connections so that we can end them if we want to destroy `server`
let sockets = new Set();
server.on('connection', socket => {
sockets.add(socket);
socket.once('close', () => sockets.delete(socket)); // Stop tracking closed sockets
});
server.destroy = () => {
for (let socket of sockets) socket.destroy();
sockets.clear();
return new Promise((rsv, rjc) => server.close(err => err ? rjc(err) : rsv()));
};
return server;
};
let server = destroyableServer(http.createServer((req, res) => {
// ...
}));
later(() => server.destroy()); // Reliably closes the server almost immediately!
Note the overhead of entering every unique socket object into a Set

Categories

Resources