Will ajax in beforeunload reliably execute? - javascript

I have a HTML5 application that needs to send a disconnect ajax request when the user changes/refreshes the page. I am currently using this code:
window.addEventListener("beforeunload", function(event) {
$.ajax({
url: api_disconnect,
data: { identifier: token },
method: "GET"
});
});
I don't need to process the response, or even ensure that the browser receives a response. My question is, can I rely on the server receiving the request?
And if not, how can I accomplish this? Currently I have the app send an "I'm alive!" request every 15 seconds (which already feels like too much). I want the server to know the second the user disconnects.
To clarify, I know that if the browser/computer crashes there's nothing I can do about that. That's what the heartbeat is for. I just mean in a normal use case, when the user closes/changes/refreshes the page.

You cannot 100% rely on the ajax call getting through. You can test many browsers and operating systems and determine which ones will usually get the ajax call sent before the page is torn down, but it is not guaranteed to do so by any specification.
The heartbeat like you are using is the most common work-around. That will also cover you for a loss in network connection or a power-down or computer sleep mode or browser crash which the beforeunload handler will not.
Another work-around I've seen discussed is to use a socket.io connection to the server. Since the socket.io connection has both a small, very efficient heartbeat and the server will see the socket get closed when the page is closed, you kind of get the best of both worlds since you will see an abnormal shut-down via the heartbeat and you will see a normal shut-down immediately via the webSocket connection getting closed.

Related

How detect changes of an api

I have a api that returns if the building is open and how much peapole are in there.
Now i want my Discord Bot to send a message when the Building opens.
How do i do that?
if the api recives a request the response is looks this :
state: {
open: false/true
}
It may be helpful to clear out the terminology: the "API" in this context is the endpoints exposed by the server and their request/response schemas (you can think of it as the fields you send and receive back). Now, this doesn't change in your case: it's the same endpoint, and the same fields. What changes is the value.
Now, you are probably doing a HTTP request to a given URL, where the server is. And in HTTP world, we say that we are requesting a resource. The resource behind https://stackoverflow.com is the homepage of this website. The resource behind the endpoint you are calling is a building's state. This resource changes overtime, it may open or closed at any time, people going in and out. But the API doesn't change in this case.
Let's reword your question, so it can be clearer: How can a client know when a HTTP resource changes? If your server only exposes this endpoint to know the state of the building, the answer is a sad "it can't". Let's say that I close the building, the server knows it somehow and now the building's state is {"open": false}. But the server doesn't have any mechanism to say to your client that the state changed, the server just waits for the client to ask what the state is, and returns. Allowing a server to send data to your client without the client requesting first adds some complexity to your architecture, and although there's a bonus (the client will know of state changes as soon as possible), in your case, it may not be necessary.
One alternative is long polling, in long polling your client makes a request to the server and the server doesn't respond immediately, it... waits. Waits for an update, like a change in building's state. When an update happens, then it sends a response. The client, in turn, requests again! And waits for the server to send an update... In practice, the client will keep up with the server state. The mentioned article for long polling gives a good example: https://javascript.info/long-polling#regular-polling
The one caveat is that the server must also support long polling. If the server just returns whatever the resource's state is, then the client will keep receiving the same state over and over. Another valid solution is instead of waiting for updates, the client keeps requesting the server for every few seconds. You may miss some updates! But in some cases, it's fine to lose track of a few updates.
Ok, enough theory. What about your case? If you want to know if a door is open or closed, but don't care to know when it happens, you can just request the server every five seconds or so:
In some pseudo javascript code, and very inspired by the long polling article mentioned before:
async function subscribe() {
let buildingState = null
while (true) {
const response = await fetch("/subscribe")
if (response.status != 200) {
// An error - let's show it
showMessage(response.statusText)
}
// Get and show the message
const message = await response.json()
// a function that returns true/false if the state is different
if (stateChanged(message, buildingState)) {
updateDiscordBot(message)
buildingState = message
}
// wait five seconds and repeat
await new Promise(resolve => setTimeout(resolve, 5000));
}
}
subscribe();
This works fine. But if you want for your client to immediately know when a door is opened or closed, this is not enough: opening and closing a door is a quite fast action, and even if you request the server every second, you may lose updates. In this case, the server needs to change. Either by implementing long polling, or something like websockets... you didn't mention that the server is in your control, but if it doesn't, it may be helpful to talk with who maintains it to work out a solution.
If you only have pull access to that API then the only way to detect state change is to periodically send a request, store response, and trigger your bot on stored response change.

Correct way to handle Websocket

I've a client to server Websocket connection which should be there for 40 seconds or so. Ideally it should be forever open.
The client continually sends data to server and vice-versa.
Right now I'm using this sequence:
var socket;
function senddata(data)
{
if (!socket)
{
socket = new WebSocket(url);
socket.onopen = function (evt) {
socket.send(data);
socket.onmessage = function (evt) {
var obj = JSON.parse(evt.data);
port.postMessage(obj);
}
socket.oneerror = function (evt) {
socket.close();
socket = null;
}
socket.onclose = function(evt){
socket = null;
}
}
}
else
{
socket.send(data);
}
}
Clearly as per current logic, in case of error, the current request data may not be sent at all.
To be frank it sometimes gives error that websocket is still in connecting state. This connection breaks often due to networking issues. In short it does not work perfectly well.
I've read a better design : How to wait for a WebSocket's readyState to change but does not cover all cases I need to handle.
Also I've Googled about this but could not get the correct procedure for this.
So what is the right way to send regular data through Websockets which handles well these issues like connection break etc?
An event you don't seem to cover is onclose. Which should work really well, since it's called whenever the connection terminates. This is more reliable than onerror, because not all connection disruptions result in an error.
I personally use Socket.IO, it enables real-time bidirectional event-based communication between client and server.
It is event driven. Events such as
on connection :: socket.on('conection',callback);
and
on disconnect :: socket.on('disconnect',callback);
are built in with socket.io so it can help you with your connection concerns. Pretty much very easy to use, check out their site if you are interested.
I use two-layer scheme on client: abstract-wrapper + websocket-client:
The responsibilities of the websocket-client are interacting with a server, recovering the connection and providing interfaces (event-emitter and some methods) to abstract-wrapper.
The abstract-wrapper is a high-level layer, which interacts with websocket-client, subscribes to its events and aggregating data, when the connection is temporary failed. The abstract-wrapper can provide to application layer any interface such as Promise, EventEmitter and so on.
On application layer, I just work with abstract-wrapper and don't worry about connection or data losing. Undoubtedly, it's a good idea to have here information about the status of connection and data sending confirmation, because it's useful.
If it is necessary, I can provide some code for example
This apparently is a server issue not a problem in the client.
I don't know how the server looks like here. But this was a huge problem for me in the past when I was working on a websocket based project. The connection would continuously break.
So I created a websocket server in java, and that resolved my problem.
websockets depend on lots of settings, like if you're using servlets then servlet container's settings matter, if you're using some php etc, apache and php settings matter, for example if you create a websocket server in php and php has default time-out of 30 seconds, it will break after 30 seconds. If keep-alive is not set, the connection wont stay alive etc.
What you can do as quick solution is
keep sending pings to a server after a certain amount of time (like 2 or 3 seconds, so that if a websocket is disconnected it is known to the client so it could invoke onclose or ondisconnect, I hope you know that there is no way to find if a connection is broken other than failing to send something.
check server's keep-alive header
If you have access to server, then it's timeouts etc.
I think that would help

SignalR & IE Issue - poll is pending

I have a Problem With IE and SignalR, I'm using the it to perform a Syncing action between two databases, the Actions Completed successfully on Google Chrome / Firefox / Safari in all scenarios.
Using IE for the First time the sync performed successfully but only for one time, in the second time a pending request stack and the page stay freeze for ever.
I found a solution online which is changing the transport mode.
But page still freezing.
if (isIE()) {
$.connection.hub.start({ transport: ['serverSentEvents','foreverFrame']}).done(function () {
progressNotifier.server.DoMyLongAction();
});
}else{
$.connection.hub.start({ transport: ['serverSentEvents','longPolling'] }).done(function () {
progressNotifier.server.DoMyLongAction();
});
}
I'm Using:
SgnalR v2.1.0.0
.Net framework v4.5
jquery v1.8
is it an Issue or I'm Doing something wrong ?
Edit
my application use Jquery progress bar and i Update this progress bar using this Code:
server side:
Clients.Caller.sendMessage(msg, 5, "Accounts");
client side:
progressNotifier.client.sendMessage = function (message, value, Entity) {
pbar1.progressbar("value", nvalue);
};
it's working on Firefox so I thought it's a signalR Issue !! Now i became confused if it's working as expected then what causes this problem ?
you can try use EventSource (SSE).
I am using this:
https://github.com/remy/polyfills/blob/master/EventSource.js
but modified, for SignalR:
http://a7.org/scripts/jquery/eventsource_edited.js
I am working with it for one year, SignalR just check for window.EventSource and it works.
The solution you found online is not likely to help your issue.
I doubt your IsIE() function is correctly identifying IE. If it was, SignalR should only be attempting to establish a "foreverFrame" connection, since IE does not even support "serverSentEvents". I would not expect IE to make any "/signalr/poll" requests, because those requests are only made by the "longPolling" transport.
Also, having a "pending" poll request in the IE F12 tool's network tab is entirely expected. This is how long polling is designed to work. Basically, as soon as a message is received the client makes a new ajax request (a long poll) to retrieve new messages. If no new messages are immediately available, the server will wait (for up to 110 seconds by default in the case of SignalR, not forever) for a new message to be sent to the client before responding to the pending long poll request with the new message.
Can you clarify exactly what issue you are having other than seeing a pending poll request showing up under the network tab? It would also help if you you enabled tracing in the JS client, provided the console output, and showed all the "/signalr/..." requests in the network tab.

Is there any javascript-event which allows an action to be executed by the web-nav continually?

I'm trying to make a websocket using jQuery which is triggered continually after the load of the page. The idea, is to get information continually from the server and to display them into the web page without any refresh.
What kind of event is?
Any brilliant idea, please?
setInterval can be dangerous because of the timing of your http request/response. Better to used chained setTimeouts, e.g.
var tick = function() {
// do something here
$('foo').toggle();
setTimeout(tick, 1000); // wait 1 second and call again
};
tick();
I think an HTML5 Websocket is what you are looking for.
The WebSocket specification defines an API establishing "socket" connections between a web browser and a server. In plain words: There is an persistent connection between the client and the server and both parties can start sending data at any time.
http://html5rocks.com/en/tutorials/websockets/basics

Handling server-side aborted long-poll/comet updates in jquery

I have an application which uses an open JQuery Ajax connection to do long-polling/comet handling of updates.
Sometimes the browser and the server lose this connection (server crashes, network problems, etc, etc).
I would like the client to detect that the update has crashed and inform the user to refresh the page.
It originally seemed that I had 2 options:
handle the 'error' condition in the JQuery ajax call
handle the 'complete' condition in the JQuery ajax call
On testing, however, it seems that neither of these conditions are triggered when the server aborts the query.
How can I get my client to understand that the server has gone away?
Isn't it possible to add a setInterval() function that runs every few seconds or minutes? That way you can trigger a script that checks whether the server is still up, and if not, reset the comet connection. (I don't know what you use for the long-polling exactly though, so I don't know if it's possible to reset that connection without a page reload. If not, you can still display a message to the user).
So something like this:
var check_server = setInterval(function() {
// run server-check-script...
// if (offline) { // reset }
}, 60000);

Categories

Resources